原题链接:97. 约数之和
解题思路
根据乘法分配律,AB的所有约数之和为:
(1+p1+p12+...+p1BxC1)x(1+p2+p22+...+p2BxC2)x...x(1+pn+pn2+...+pnBxCn)
我们把改式展开,与约数集合比较。
上式中的每个括号内都是等比数列,如果使用等比数列求和公式,需要做除法。而答案还要对9901取模,mod运算只对加、减、乘有分配律,不能直接对分子,分母分别取模后再做除法,我们可以换一种思路,使用分治法进行等比数列求和。
问题:使用分治法求sum(p,c)=1+p+p2+...+pc=?
若c为奇数:
sum(p,c)=(1+p+...+p(c-1)/2)+(p(c+1)/2+...+pc)
=(1+p+...+p(c-1)/2)+p(c+1)/2x(1+p+...+p(c-1)/2)
=(1+p(c+1)/2) x sum(p,(c-1)/2)
若c为偶数,类似的:
sum(p,c)=(1+pc/2) x sum(p,(c/2)-1) + pc
每次分治(递归之后),问题的规模会缩小一半,配合快速幂即可在O(logc)的时间内求出等比数列的和。
样例代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
#define Mod 9901
int a,b;
int ksm(int a,int b)//快速幂函数
{
int ans=1;
a%=Mod;
while(b)
{
if (b&1)
ans=ans%Mod*a;
a=a%Mod*a%Mod;
b>>=1;
}
return ans;
}
long long sum(int p,int c)
{
if (c==0)
return 1;
if(c&1)
return ((1+ksm(p,(c+1)>>1))*sum(p,(c-1)>>1))%Mod;//奇数的情况下
else
return ((1+ksm(p,c>>1))*sum(p,(c>>1)-1)+ksm(p,c))%Mod;//偶数的情况下
}
int main()
{
cin>>a>>b;
int ans=1;
for (int i=2;i<=a;i++)
{
int s=0;
while(a%i==0)
{
s++;
a/=i;
}
if (s)//这句话剪枝.然后就TLE变成了AC.by POJ
ans=ans*sum(i,s*b)%Mod;
}
if (a==0)
cout<<0<<endl;//特判的情况,这里非常的阴毒,出题人用心险恶
else
cout<<ans<<endl;
return 0;
}