FZOJ1831: 【POJ 1845】sumdiv约数和
首先,我们得知道A的约数等于什么
A
=
p
1
k
1
∗
p
2
k
2
∗
⋯
∗
p
n
k
n
A=p_{1}^{k_{1}}*p_{2}^{k_{2}}* \cdots*p_{n}^{k_{n}}
A=p1k1∗p2k2∗⋯∗pnkn其中pn为质数,kn为任意整数。
根据幂的运算,易得
A
B
=
p
1
k
1
B
∗
p
2
k
2
B
∗
⋯
∗
p
n
k
n
B
A^{B}=p_{1}^{k_{1}B}*p_{2}^{k_{2}B}* \cdots*p_{n}^{k_{n}B}
AB=p1k1B∗p2k2B∗⋯∗pnknB其次,我们还有一个约数和公式
S
=
(
1
+
p
1
+
p
1
2
+
⋯
+
p
1
k
1
)
∗
(
1
+
p
2
+
p
2
2
+
⋯
+
p
2
k
1
)
⋯
S=(1+p_{1}+p_{1}^{2}+\cdots+p_{1}^{k_{1}})*(1+p_{2}+p_{2}^{2}+\cdots+p_{2}^{k_{1}})\cdots
S=(1+p1+p12+⋯+p1k1)∗(1+p2+p22+⋯+p2k1)⋯根据等比数列以及上面的公式知:
S
=
(
1
−
p
1
k
1
B
+
1
1
−
p
1
)
∗
(
1
−
p
2
k
2
B
+
1
1
−
p
2
)
⋯
S=(\frac{1-p_1^{k_1B+1}}{1-p_1})*(\frac{1-p_2^{k_2B+1}}{1-p_2})\cdots
S=(1−p11−p1k1B+1)∗(1−p21−p2k2B+1)⋯
即:
S
=
(
p
1
k
1
B
+
1
−
1
p
1
−
1
)
∗
(
p
2
k
2
B
+
1
−
1
p
2
−
1
)
⋯
S=(\frac{p_1^{k_1B+1}-1}{p_1-1})*(\frac{p_2^{k_2B+1}-1}{p_2-1})\cdots
S=(p1−1p1k1B+1−1)∗(p2−1p2k2B+1−1)⋯
直接暴力求解等比数列可能会超时,所以很自然地想到了逆元(费马小定理),但是此时有一点要注意:pi-1可能是9901的倍数,就会不存在逆元。
对于
A
B
≡
x
(
m
o
d
m
)
\frac{A}{B} \equiv x(mod\ m)
BA≡x(mod m)
等价于:
A
B
+
k
m
=
x
\frac{A}{B}+km= x
BA+km=x通分得:
A
+
k
B
m
B
=
x
\frac{A+kBm}{B}= x
BA+kBm=x即:
A
(
m
o
d
B
m
)
B
=
x
\frac{A(mod\ Bm)}{B} = x
BA(mod Bm)=x
应用这个公式,用到快速幂取模,在快速幂取模中一步乘法可能会溢出long long ,因此有添加了一个对于大数a*b (mod m)的函数。因为最终的模数不是mod,而是
m
o
d
∗
(
k
i
−
1
)
mod*(k_{i}-1)
mod∗(ki−1);
贴代码
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int mac=50009;
const int MOD=9901;
ll B,n,num;
struct node{
ll p,k;
}yin[mac];
inline ll mul(ll a,ll b,ll mod){//防止爆long long
ll s=0;
while(b){
if(b&1)
s=(s+a)%mod;
a=(a*2)%mod;
b>>=1;
}
return s<0?s+mod:s;
}
inline ll mi(ll a,ll b,ll mod){
ll sum=1;
while(b>0){
if(b&1) sum=mul(sum,a,mod);
a=mul(a,a,mod);
b>>=1;
}
return sum<0?(sum+mod):sum;
}
int main(){
// freopen("1831.in","r",stdin);
scanf("%lld%lld",&n,&B);
ll A=n;
num=1;
for(ll i=2;i<=sqrt(n+0.0);i++){
if(n%i==0){
yin[num++].p=i;
while(n%i==0){
yin[num-1].k++;
n/=i;
}
}
}
if(n>1){//如果a 为素数
yin[num++].p=n;
yin[num-1].k++;
}
ll ans=1;
for(ll i=1;i<=num;i++){
ll b=((yin[i].k)*(B));
ll p=mi(yin[i].p , b+1, MOD*(yin[i].p-1));
ans*=(p-1)/(yin[i].p-1);
ans%=MOD;
}
printf("%lld\n",ans);
return 0;
}
感谢博主Sharp_Edge_Of_Defens的博客,在他的启发下,本人才做出这道题。
参考自 https://blog.csdn.net/u012860428/article/details/41315081