首先我们知道一个数可以分解成以下形式
X = p 1 a 1 ∗ . . . ∗ p n a n X=p_1^{a_1}*...*p_n^{a_n} X=p1a1∗...∗pnan
则约数和为 ( 1 + p 1 1 + p 1 2 + . . . + p 1 a 1 ) ∗ . . . ∗ ( 1 + p n 1 + p n 2 + . . . + p n a n ) (1+p_1^1+p_1^2+...+p_1^{a_1})*...*(1+p_n^1+p_n^2+...+p_n^{a_n}) (1+p11+p12+...+p1a1)∗...∗(1+pn1+pn2+...+pnan)
对于 x y = ( p 1 a 1 ∗ . . . ∗ p n a n ) y = ( p 1 a 1 ∗ y ∗ . . . ∗ p n a n ∗ y ) x^y = (p_1^{a_1}*...*p_n^{a_n})^y = (p_1^{a_1*y}*...*p_n^{a_n*y}) xy=(p1a1∗...∗pnan)y=(p1a1∗y∗...∗pnan∗y)
同理可以写出约数和,这里省略;
思路一、分治
我们设 s u m ( p , k ) = p 0 + p 1 + . . . + p k − 1 sum(p,k) = p^0+p^1+...+p^{k-1} sum(p,k)=p0+p1+...+pk−1
当
k
k
k为偶数时,上式可以改写成
(
p
0
+
p
1
+
.
.
.
+
p
k
/
2
−
1
)
+
(
p
k
/
2
+
.
.
.
+
p
k
−
1
)
(p^0+p^1+...+p^{k/2-1})+(p^{k/2}+...+p^{k-1})
(p0+p1+...+pk/2−1)+(pk/2+...+pk−1)
==>
s
u
m
(
p
,
k
/
2
)
+
p
k
/
2
(
p
0
+
p
1
+
.
.
.
+
p
k
/
2
−
1
)
sum(p,k/2)+p^{k/2}(p^0+p^1+...+p^{k/2-1})
sum(p,k/2)+pk/2(p0+p1+...+pk/2−1)
==>
s
u
m
(
p
,
k
/
2
)
+
s
u
m
(
p
,
k
/
2
)
∗
p
k
/
2
sum(p,k/2)+sum(p,k/2)*p^{k/2}
sum(p,k/2)+sum(p,k/2)∗pk/2
==>
(
1
+
p
k
/
2
)
∗
s
u
m
(
p
,
k
/
2
)
(1+p^{k/2})*sum(p,k/2)
(1+pk/2)∗sum(p,k/2)
当 k k k为奇数时,那么 k − 1 k-1 k−1就是偶数,我们将最后一项提取出来,可得 p k − 1 + s u m ( p , k − 1 ) p^{k-1}+sum(p,k-1) pk−1+sum(p,k−1)
Code
#include <iostream>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int mod = 9901;
//x^y%mod
ll qpow(ll x,ll y){
ll ret = 1;
ll base = x;
while(y){
if(y&1){
ret*=base;
ret%=mod;
}
base*=base;
base%=mod;
y>>=1;
}
return ret;
}
//sum(p,k) = p^0 + ... + p^(k-1)
int sum(int p,int k){
if(k==1) return 1;//p^0 = 1
if(k&1){
return (qpow(p,k-1)%mod + sum(p,k-1)%mod)%mod;
}
//k is even
return ((1+qpow(p,k/2))%mod*sum(p,k/2)%mod)%mod;
}
unordered_map<int,int> um;
void divide(ll x){
for(int i=2;i*i<=x;++i){
if(x%i == 0){
while(x%i == 0){
++um[i];
x/=i;
}
}
}
if(x>1) ++um[x];
}
int main(){
int a,b;
cin >> a >> b;
divide(a);
int p,k;
ll ans = 1;
for(auto x : um){
p = x.first,k=x.second*b;
ans=(ans%mod*sum(p,k+1)%mod)%mod;
}
if(a == 0) ans = 0;
cout << ans << '\n';
return 0;
}
思路二、公式法
对于
p
0
+
p
1
+
.
.
.
+
p
k
p^0+p^1+...+p^{k}
p0+p1+...+pk可以使用等比数列求和公式求得一个式子,如下;
p
k
+
1
−
1
p
−
1
\frac{p^{k+1}-1}{p-1}
p−1pk+1−1
因为存在模运算,因此需要使用逆元
我们设要模的那个数为
m
o
d
mod
mod
判断是否存在逆元
当
p
−
1
%
m
o
d
=
0
p-1\%mod=0
p−1%mod=0时,
p
%
m
o
d
=
1
p\%mod=1
p%mod=1
因此
(
p
0
+
p
1
+
.
.
.
+
p
k
)
(p^0+p^1+...+p^{k})
(p0+p1+...+pk)一共有k+1项,对于每个数来说,在模
m
o
d
mod
mod下都是1,因此一共就是
k
+
1
k+1
k+1;
即
(
p
0
+
p
1
+
.
.
.
+
p
k
)
%
m
o
d
=
k
+
1
(p^0+p^1+...+p^{k})\%mod=k+1
(p0+p1+...+pk)%mod=k+1
当 p − 1 % m o d ≠ 0 p-1\%mod\neq0 p−1%mod=0时,存在逆元
那么直接使用费马小定理求逆元即可;
不会求逆元请看我这篇博客
Code
#include <iostream>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int mod = 9901;
//x^y%mod
ll qpow(ll x,ll y){
ll ret = 1;
ll base = x;
while(y){
if(y&1){
ret*=base;
ret%=mod;
}
base*=base;
base%=mod;
y>>=1;
}
return ret;
}
unordered_map<ll,ll> um;
void divide(ll x){
for(int i=2;i*i<=x;++i){
if(x%i == 0){
while(x%i == 0){
++um[i];
x/=i;
}
}
}
if(x>1) ++um[x];
}
int main(){
ll a,b;
cin >> a >> b;
divide(a);
ll p,k;
ll ans = 1;
for(auto x : um){
p = x.first,k=x.second*b;
if((p-1)%mod == 0){
//没有逆元
ans = (ans%mod*(k+1)%mod)%mod;
}else{
ans = (ans%mod*(qpow(p,k+1)-1)%mod*qpow(p-1,mod-2)%mod)%mod;
}
}
if(a == 0) ans = 0;
//乘了逆元可能出现负数
//而c++的模运算不一定是正数
//因此需要这样写
cout << (ans%mod+mod)%mod << '\n';
return 0;
}