poj 1845 Sumdiv(约数和,乘法逆元)
Posted zylak
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj 1845 Sumdiv(约数和,乘法逆元)相关的知识,希望对你有一定的参考价值。
题目:
求AB的正约数之和。
输入:
A,B(0<=A,B<=5*107)
输出:
一个整数,AB的正约数之和 mod 9901。
思路:
根据正整数唯一分解定理,若一个正整数表示为:A=p1^c1 * p2^c2 * ...... pm^cm 则其正约数之和可以表示为:S=(1+p1+p1^2+......p1^c1)*(1+p2+p2^2+......p2^c2)*......(1+pm+pm^2+......pm^cm)
那么AB就可以表示为:S‘=(1+p1+p1^2+......p1^(c1*B))*(1+p2+p2^2+......p2^(c2*B))*......(1+pm+pm^2+......pm^(cm*B))
这样,我们发现每一项(以第一项为例)(1+p1+p1^2+......p1^(c1*B))是一个等比数列,根据求和公式易得:(p1^(c1*B+1)-1)/(p1-1)同理,后面的式子也是。那么接下来我们可以通过快速幂求解分子
部分。分母部分需要用到(p1-1)的乘法逆元。因为模数9901是质数,所以只要(p1-1)不是9901的倍数,那么它们就互质,根据费马小定理,乘法逆元就是(p1-2)。特别的,如果(p1-1)是9901
的倍数,那么就有(p1-1)| 9901,即:p1%9901=1,所以这一项就变成了:(1+1+1^2+……+1^(c1*B))%9901=(c1*B)+1 (mod 9901) 。具体代码如下:
#include<cstdio> const int mod=9901; typedef long long ll; int a,b,ans=1; int factor[1000005],fc[1000005],cnt; void div(int x) { for (int i=2;i*i<=x;i++) { if (x%i==0) { factor[++cnt]=i; while (x%i==0) x/=i,fc[cnt]++; } } if (x>1) factor[++cnt]=x,fc[cnt]=1; } int ksm(int a,ll b) { int re=1; while (b) { if (b&1) re=(1ll*re*a)%mod; a=(1ll*a*a)%mod; b>>=1; } return re; } int main() { scanf ("%d%d",&a,&b); div(a); for (int i=1;i<=cnt;i++) { int fac=factor[i]; if ((fac-1) % 9901 == 0)//特判分母是否是9901的倍数 { ans = (ans%mod * (1ll*b*fc[i]+1)%mod) % mod; continue; } int fm=( ksm(fac,1ll*b*fc[i]+1)-1+mod )%mod;//分母 int fzny=( ksm(fac-1,mod-2) )%mod;//分子逆元 ans = (1ll*ans * fm%mod * fzny%mod)%mod; } printf("%d",ans); return 0; }
以上是关于poj 1845 Sumdiv(约数和,乘法逆元)的主要内容,如果未能解决你的问题,请参考以下文章
POJ1845 Sumdiv - 乘法逆元+快速幂A^B的约数个数和