poj1845 Sumdiv 题解报告

mac2022-06-30  90

题目传送门

【题目大意】

求$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\n",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\n");return 0;}//注意特判 38 if(b==0) {printf("1\n");return 0;} 39 divide(a); 40 go(i,1,m) 41 ans=ans*sum(p[i],b*c[i])%mod; 42 printf("%d\n",ans); 43 return 0; 44 } 递归法

 

转载于:https://www.cnblogs.com/THWZF/p/11248143.html

相关资源:JAVA上百实例源码以及开源项目
最新回复(0)