97.约数之和

原题链接: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;
}
posted @ 2020-12-18 18:33  hnkjdx_react  阅读(139)  评论(0编辑  收藏  举报