题目
Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. Determine S modulo 9901 (the rest of the division of S by 9901).
大意
给定两个自然数A,B。找出 A B A^B AB的所有因子之和,最后结果对9901取模。
Input
The only line contains the two natural numbers A and B, ( 0 ≤ A , B ≤ 50000000 ) (0 \le A,B \le 50000000) (0≤A,B≤50000000)separated by blanks.
Ouput
The only line of the output will contain S modulo 9901.
Sample Input
2 3
Sample Output
15
题目分析
题目需要求解
A
B
A^B
AB的所有因子之和,先看样例,可以看出15其实就是
2
0
+
2
1
+
2
2
+
2
3
2^0+2^1+2^2+2^3
20+21+22+23,同样的,我们还可以举例3 3,这里的结果是
3
0
+
3
1
+
3
2
+
3
3
3^0+3^1+3^2+3^3
30+31+32+33。但仔细分析,之所以可以直接求其等比数列之和,原因是因为2和3皆是质数,对4,9,12等合数若是采用该方法很显然是错误的。那我们可否将这些合数变成质数呢?我们知道
a
b
=
(
c
×
d
)
b
a^b = (c\times d)^b
ab=(c×d)b,那我们可以把合数a转化为多个质数相乘的结果,这里可以应用到数学上的唯一分解定理。
a
b
=
p
1
k
1
×
b
×
⋯
×
p
n
k
n
×
b
a^b = p_1^{k_1\times b}\times \dots \times p_n^{k_n\times b}
ab=p1k1×b×⋯×pnkn×b,其中
p
1
,
p
2
…
p
n
p_1,p_2\dots p_n
p1,p2…pn均为质数。
此时我们便可以对每一项通过等比数列求和的方式得到答案。但是因为之前学的
a
1
×
(
1
−
q
n
)
1
−
q
\frac{a_1\times (1-q^n)}{1-q}
1−qa1×(1−qn)可能产生的结果为小数,在取模时,仍需要逆元操作。那么此处可以换一种求等比数列和的方法。
等比二分求和:
n
=
0
n = 0
n=0时,
S
n
=
1
S_n = 1
Sn=1
n
%
2
=
0
n \% 2 =0
n%2=0时,
n
%
2
=
1
n\%2=1
n%2=1时,
代码
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod = 9901;
int isprime[10005];
int prime[10005];
int cnt = 0,k = 0;
int q[10000];
int p[10000];
void getprime(){//欧拉筛
memset(isprime,1,sizeof(isprime));
isprime[1] = 0;
for(int i = 2;i<10005;++i){
if(isprime[i])
prime[++cnt] = i;
for(int j = 3;j<=cnt&&(i*prime[j])<10005;++j){
isprime[i*prime[j]] = 0;
if(i%prime[j]==0) break;
}
}
}
int qpow(ll a,ll b){//快速幂
int ans = 1;
a %= mod;
while(b!=0){
if(b&1)
ans = ans*a%mod;
a = (a%mod)*(a%mod)%mod;
b>>=1;
}
return ans;
}
void break_down(ll a,ll b){//唯一分解定理
for(int i = 1;i<=cnt;++i){
if(a%prime[i]==0){
int t = 0;
while(a%prime[i]==0){
++t;
a/=prime[i];
}
p[++k] = prime[i];
q[k] = t*b;
if(a==1) break;
}
if(prime[i] > a)
break;
}
if(a!=1){
p[++k] = a;
q[k] = b;
}
}
ll sum(ll a,ll b){//等比二分求和(等比求和公式对mod不可取)
if(a==0) return 0;
if(b==0) return 1;
if(b&1)
return ((1+qpow(a,b/2+1))%mod*sum(a,b/2)%mod)%mod;
else
return ((1+qpow(a,b/2+1))%mod*sum(a,b/2-1)%mod+qpow(a,b/2)%mod)%mod;
}
int main(){
getprime();
ll a,b;
ll t1,t2,ans = 1;
cin >> a >> b;
break_down(a,b);
for(int i = 1;i<=k;++i){
t1 = sum(p[i],q[i])%mod;
ans *= t1;
ans %= mod;
}
cout << ans <<endl;
return 0;
}