题解POJ1845 Sumdiv(乘法逆元+约数和)
Posted brokenstring
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解POJ1845 Sumdiv(乘法逆元+约数和)相关的知识,希望对你有一定的参考价值。
POJ1845:http://poj.org/problem?id=1845
思路:
AB可以表示成多个质数的幂相乘的形式:AB=(a1n1)*(a2n2)* ...*(amnm)
根据算数基本定理可以得约数之和sum=(1+a1+a12+...+a1n1)*(1+a2+a22+...+a2n2)*...*(1+am+am2+...+amnm) mod 9901
对于每个(1+ai+ai2+...+aini) mod 9901=(ai(ni+1)-1)/(ai-1) mod 9901 (等比数列前n项目和)分母可用快速幂算出
因为9901是质数,只要ai-1不是9901的倍数就只要计算ai-1的乘法逆元inv(用费马小定理),再乘(ai(ni+1)-1) 直接算出ans
PS:若ai-1是9901的倍数 此时乘法逆元不存在 但是ai mod 9901=1 所以1+ai+ai2+...+aini=1+1+...+1=ni+1
代码:
#include<iostream> #include<cmath> #include<cstdio> using namespace std; #define mod 9901 int a,b,m,ans=1; int p[20],c[20];//p是质数 c是指数 void divide(int n) { m=0; for(int i=2;i*i<=n;i++) { if(n%i==0) { p[++m]=i; c[m]=0; while(n%i==0) { n/=i; c[m]++; } } } if(n>1) { p[++m]=n; c[m]=1; } } int quickpow(int a,long long b) { int c=1; for(;b;b>>=1) { if(b&1) c=(long long)c*a%mod; a=(long long)a*a%mod; } return c; } int main() { cin>>a>>b; divide(a);//分解A的质因数 b到后面在乘上 for(int i=1;i<=m;i++) { if((p[i]-1)%mod==0)//特判当ai-1是9901的倍数 乘法逆元不存在 { ans=((long long)b*c[i]+1)%mod*ans%mod; continue; } int x=quickpow(p[i],(long long)b*c[i]+1);//快速幂求分母 x=(x-1+mod)%mod; int y=p[i]-1; y=quickpow(y,mod-2);//根据费马小定理求乘法逆元 ans=(long long)ans*x%mod*y%mod; } cout<<ans; }
以上是关于题解POJ1845 Sumdiv(乘法逆元+约数和)的主要内容,如果未能解决你的问题,请参考以下文章
POJ1845 Sumdiv - 乘法逆元+快速幂A^B的约数个数和