欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

97. 约数之和(分治)

程序员文章站 2022-05-08 19:06:20
...

97. 约数之和(分治)

a b a^b ab的约数和 模 p p p的值。

σ ( a b ) ( m o d p ) \large \sigma(a^b)\pmod{p} σ(ab)(modp)

首先利用算数基本定理:

a b = ( p 1 k 1 p 2 k 2 … p m k m ) b = p 1 k 1 b p 2 k 2 b … p m k m b \large a^b=(p_1^{k_1}p_2^{k_2}\dots p_m^{k_m})^b=p_1^{k_1b}p_2^{k_2b}\dots p_m^{k_mb} ab=(p1k1p2k2pmkm)b=p1k1bp2k2bpmkmb

σ ( n ) = ( 1 + p 1 + p 1 2 ⋯ + p 1 k 1 ) ( 1 + p 2 + p 2 2 ⋯ + p 2 k 2 ) … ( 1 + p m + p m 2 + ⋯ + p m k m ) = σ ( p 1 k 1 ) σ ( p 2 k 2 ) … σ ( p m k m ) \sigma(n)=(1+p_1+p_1^2\dots+p_1^{k_1})(1+p_2+p_2^2\dots+p_2^{k_2})\dots (1+p_m+p_m^2+\dots+ p_m^{k_m})=\sigma(p_1^{k_1})\sigma(p_2^{k_2})\dots \sigma(p_m^{k_m}) σ(n)=(1+p1+p12+p1k1)(1+p2+p22+p2k2)(1+pm+pm2++pmkm)=σ(p1k1)σ(p2k2)σ(pmkm)

所以我们只需要求出 σ ( p i k i b ) \large \sigma(p_i^{k_ib}) σ(pikib)即可。

这个是一个等比数列,有两种方法求解:

1.分治法。

2.公式法。

分治法:令 σ ( p k − 1 ) = f ( p , k ) = p 0 + p 1 + ⋯ + p k − 1 \sigma(p^{k-1})=f(p,k)=p^0+p^1+\dots+p^{k-1} σ(pk1)=f(p,k)=p0+p1++pk1

k k k为偶数时:
f ( p , k ) = ( p 0 + p 1 + ⋯ + p k 2 − 1 ) + ( p k 2 + ⋯ + p k − 1 ) = p k 2 ( 1 + f ( a , k 2 ) ) f(p,k)=(p_0+p_1+\dots+p^{\small\dfrac{k}{2}-1})+(p^{\small\dfrac{k}{2}}+\dots+p_{k-1})=p^{\small\dfrac{k}{2}}(1+f(a,\dfrac{k}{2})) f(p,k)=p0+p1++p2k1)+(p2k++pk1)=p2k(1+f(a,2k))

k k k为奇数时,拆掉最后面一项变为偶数情况即可。

代码

// Problem: 约数之和
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/99/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// Date: 2021-07-02 00:16:08
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=9901;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]); 
}
vector<PII>v;
void init(int n){
	for(int i=2;i*i<=n;i++)
		if(n%i==0){
			PII x;
			x.fi=i,x.se=0;
			while(n%i==0) x.se++,n/=i;
			v.pb(x);
		}
	if(n>1) v.pb(n,1);
}
ll ksm(ll a,ll n,ll m=mod){
	ll ans=1;
	while(n){
		if(n&1) ans=ans*a%m;
		a=a*a%m;
		n>>=1;
	}
	return ans;
}
ll f(ll a,ll k){
	if(k==1) return 1;
	if(k%2==0) return (ksm(a,k/2)+1)*f(a,k/2)%mod;
	return (f(a,k-1)+ksm(a,k-1))%mod;
}
int main(){
	int a,b;scanf("%d%d",&a,&b);
	init(a);
	ll ans=1;
	for(auto x:v){
		int u=x.fi,v=x.se*b;
		ans=ans*f(u,v+1)%mod;
	}
	if(!a) ans=0;
	printf("%lld\n",ans);
	return 0;
}

公式法:利用等比数列求和公式即可。

σ ( p k − 1 ) = f ( p , k ) = p k − 1 p − 1 \sigma(p^{k-1})=f(p,k)=\dfrac{p^{k}-1}{p-1} σ(pk1)=f(p,k)=p1pk1

这里用快速幂+逆元即可。

注意当 ( p − 1 ) ( m o d m o d ) = 0 (p-1)\pmod {mod}=0 (p1)(modmod)=0时,答案即为 k k k,因为 p ( m o d m o d ) = 1 p\pmod{mod}=1 p(modmod)=1

相关标签: 数论