约数之和
Posted zhangjianjunab
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了约数之和相关的知识,希望对你有一定的参考价值。
题目
题解
思路很神奇,把(A)分解成(a_1^{b_1}*a_2^{b_2}*a_3^{b_3}*...*a_n^{b_n})((a_i)为质数)。
那么,我们现在就得到了他的质因数以及每个质因数的个数了,而它的约数肯定是在其中选择的几个数字相乘得到的,换个角度想,其实就是对于每个质因数选择多少个的问题。
不难想到,当选(0)个(a_i)和选(j)个(a_i)时的约数个数是一样的,而且在除去了(a_i)这些约束甚至还是一样的。
用乘法分配律不难得出约数之和是((a_1^0+a_1^1+a_1^2+a_1^3+...+a_1^{b_1*B})*...*(a_n^0+a_n^1+a_n^2+a_n^3+...+a_n^{b_n*B}))
而且对于每个括号内,是一个等比数列,以(a_1)为例子,公式为:(frac{a_1^{b_1*B+1}-1}{a_1-1}),但是需要注意的是,如果(a_i\%9901=1)的话,这个公式就会废掉,需要特判,当然,因为涉及到了除法,所以需要乘法逆元,而(9901)是个质数,所以(x^{9899})就是(x)的乘法逆元了,这些都只需要快速幂就可以解决了。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#define N 2100000
using namespace std;
typedef long long LL;
LL n,m,p=9901;
LL a[N]/*约数*/,b[N]/*次数*/,top;
inline LL ksm(LL x,LL y)
{
LL ans=1;x%=p;
while(y)
{
if(y&1)ans=(ans*x)%p;
x=(x*x)%p;y>>=1;
}
return ans;
}
LL dfs(LL x,LL y)
{
a[++top]=y%p;
while(x%y==0)b[top]++,x/=y;
return x;
}
void fenjie(int x)
{
int y=sqrt(x);
for(LL i=2;i<=y && i<=x/*其实如果把后面的if去掉然后改成i<=x也对,但是会慢*/;i++)
{
if(x%i==0)x=dfs(x,i);
}
if(x!=1)
{
a[++top]=x;
b[top]=1;
}
}
int main()
{
scanf("%lld%lld",&n,&m);
if(n==0)printf("0
");
else if(n==1 || m==0)printf("1
");
else
{
fenjie(n);
for(int i=1;i<=top;i++)b[i]*=m;
LL ans=1;
for(int i=1;i<=top;i++)
{
if(a[i]==1)ans=(ans*(b[i]+1))%p;
else ans*=((ksm(a[i],b[i]+1)+p-1/*+p防止<0*/)%p)*ksm(a[i]-1+p/*防止<0*/,p-2),ans%=p;
}
printf("%lld
",ans);
}
return 0;
}
以上是关于约数之和的主要内容,如果未能解决你的问题,请参考以下文章