【题目大意】
求$A^B$的所有约数之和($mod 9901$)
【思路分析】
把$A$分解质因数,则$$A=p_1^{c_1}*p_2^{c_2}*…*p_n^{c_n}$$
于是可以得到
$$A^B=p_1^{B*c_1}*p_2^{B*c_2}*…*p_n^{B*c_n}$$
于是$A^B$的所有约数之和就是
$$(1+p_1+…+p_1^{B*c_1})*…*(1+p_n+…+p_n^{B*c_n})$$
上式的每个括号中都是等比数列,如果用求和公式,需要做除法,而$mod$运算的分配律并不适用于除法,所以我们要考虑转化。
1.递归(分治法)
把问题分成规模更小的同类子问题,然后递归求解
设$sum(p,c)=1+p+p^2+…+p^c$
若$c$为奇数,则
$$sum(p,c)=(1+p+…+p^{frac{c-1}{2}})+(p^{frac{c+1}{2}}+…+p^c)$$
$$=(1+p+…+p^{frac{c-1}{2}})+p^{frac{c+1}{2}}*(1+p+…+p^{frac{c-1}{2}})$$
$$=(1+p^{frac{c+1}{2}})*sum(p,frac{c-1}{2})$$
若$c$为偶数,则
$$sum(p,c)=(1+p^{frac{c}{2}})*sum(p,frac{c}{2}-1)+p^c$$
2.逆元法
关于乘法逆元的知识详见数论专题学习笔记,这里只放一下代码了。
【代码实现】
1 #include<cstdio> 2 #define rg register 3 #define go(i,a,b) for(rg int i=a;i<=b;i++) 4 #define ll long long 5 using namespace std; 6 int a,b,m,ans=1; 7 const int mod=9901; 8 int p[20],c[20]; 9 void divide(int x){//分解质因数 10 m=0; 11 for(rg int i=2;i*i<=x;i++){ 12 if(x%i==0){ 13 p[++m]=i,c[m]=0; 14 while(x%i==0) x/=i,c[m]++; 15 } 16 } 17 if(x>1) p[++m]=x,c[m]=1; 18 return; 19 } 20 int ksm(int x,ll y){ 21 int as=1; 22 while(y){ 23 if(y&1) as=(ll)as*x%mod; 24 x=(ll)x*x%mod; 25 y>>=1; 26 } 27 return as; 28 } 29 int main(){ 30 scanf("%d%d",&a,&b); 31 divide(a); 32 go(i,1,m){ 33 if((p[i]-1)%mod==0){//特判没有逆元的情况 34 ans=((ll)b*c[i]+1)%mod*ans%mod; 35 continue; 36 } 37 int x=ksm(p[i],(ll)b*c[i]+1);//分子 38 x=(x-1+mod)%mod; 39 int y=p[i]-1;//分母 40 y=ksm(y,mod-2);//费马小定理求逆元 41 ans=(ll)ans*x%mod*y%mod; 42 } 43 printf("%d ",ans); 44 return 0; 45 }
1 #include<cstdio> 2 #define rg register 3 #define go(i,a,b) for(rg int i=a;i<=b;i++) 4 #define ll long long 5 using namespace std; 6 int a,b,m,ans=1; 7 const int mod=9901; 8 int p[20],c[20]; 9 void divide(int x){//分解质因数 10 m=0; 11 for(rg int i=2;i*i<=x;i++){ 12 if(x%i==0){ 13 p[++m]=i,c[m]=0; 14 while(x%i==0) x/=i,c[m]++; 15 } 16 } 17 if(x>1) p[++m]=x,c[m]=1; 18 return; 19 } 20 int ksm(int x,ll y){ 21 int as=1; 22 while(y){ 23 if(y&1) as=(ll)as*x%mod; 24 x=(ll)x*x%mod; 25 y>>=1; 26 } 27 return as; 28 } 29 int sum(int x,int y){ 30 if(y==0) return 1; 31 if(y==1) return x+1; 32 if(y&1) return (1+ksm(x,(y+1)/2))*sum(x,(y-1)/2)%mod; 33 else return (1+ksm(x,y/2))*sum(x,y/2-1)%mod+ksm(x,y)%mod; 34 } 35 int main(){ 36 scanf("%d%d",&a,&b); 37 if(a==0) {printf("0 ");return 0;}//注意特判 38 if(b==0) {printf("1 ");return 0;} 39 divide(a); 40 go(i,1,m) 41 ans=ans*sum(p[i],b*c[i])%mod; 42 printf("%d ",ans); 43 return 0; 44 }