POJ1845(约数之和)

自闭的人的题解

POJ1845 约数之和

题目描述:
给你两个整数A、B,让你求出a^b中所有的约数的和膜上9901的值。
输入 :
两个正整数A,B
输出 :
一个正整数表示答案
样例:
IN :2 3
OUT : 15


这道题,我一开始其实是只有暴力的思路的。
但是,又重新去思考一下,因为求的是所有约数的和,所以我们就可以将A分解质因数

[A=p_{1}^{c_{1}} * p_{2}^{c_{2}} * p_{3}^{c_{3}} * ldots * p_{n}^{c n_{+1}} ]

又因为要^B,所以我们最后得到的式子就是这个:

[mathrm{A}=p_{1}^{B * c_{1}} * p_{2}^{B * c_{2}} * p_{3}^{B * c_{3}} * ldots * p_{n}^{B * c_{n}} ]

所以A^B的约数为就是:

[egin{array}{c}{left{p_{1}^{k_{1}} * p_{2}^{k_{2}} * ldots * p_{n}^{k_{n}} ight}} \ {0 leq k_{i} leq B * c_{i}(1 leq i leq n)}end{array} ]

再将中间的约数拆开来,得到:

[left(1+p_{1}+p_{1}^{2}+p_{1}^{3}+p_{1}^{4} ldots+p_{1}^{B cdot c_{1}} ight) *left(1+p_{2}+p_{2}^{2}+p_{2}^{3}+p_{2}^{4} ldots+p_{2}^{B cdot c_{2}} ight) ldots *left(1+p_{n}+p_{n}^{2}+p_{n}^{3}+p_{n}^{4} ldots+p_{n}^{B cdot c_{n}} ight) ]

所以我们的问题就转化到了对于这个式子进行取模求和,但是,我们如何进行求和呢?
因为其中全部都是等比数列,所以如果我们就可以考虑使用等比数列求和公式进行求解,但是,我们这中间有除法,所以我们的取模操作就会出问题。所以这个思路的正确性是无法保证的。
我们可以再换一种思路,可以将问题进行

分治

我们设出一个函数sum(p,c)表示约数对答案造成的影响。

[operatorname{sum}(p, c)=1+p+p^{2}+p^{3}+p^{4} ldots+p^{c} ]

我们考虑对于c为奇数时,

[egin{aligned} operatorname{sum}(p, c) &=1+p+p^{2}+p^{3}+p^{4} ldots+p^{c} \ &=left(1+p+cdots+p^{frac{c-1}{2}} ight)+left(p^{frac{c+1}{2}}+cdots+p^{c} ight) \ &=left(1+p+cdots+p^{frac{c-1}{2}} ight)+p^{frac{c+1}{2}}left(1+p+cdots+p^{frac{c-1}{2}} ight) \ &=left(1+p+cdots+p^{frac{c-1}{2}} ight) *left(1+p^{frac{c+1}{2}} ight) \ &=left(1+p^{frac{c+1}{2}} ight) * operatorname{sum}left(p, frac{c-1}{2} ight) end{aligned} ]

当c为偶数时,同理为了满足我们刚刚推出来的式子,我们把最后一个p单独拿出来,这样我们就可以得到跟奇数一样的情况。
所以偶数的公式为:

[operatorname{sum}(p, c)=left(1+p^{frac{c}{2}} ight) * operatorname{sum}left(p, frac{c}{2}-1 ight)+p^{c} ]

这样,我们两个公式都已经推出来了,我们就可以进行操作(具体细节在代码中显示)。
代码:


#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
template <typename type>
void scan(type &x){
    type f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
#define mod 9901
#define int ll
#define ll long long
ll ksm(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1){
            ans=ans*a%mod;
        }
        a=(a*a)%mod;
        b>>=1;
    }
    return ans%mod;
}\快速幂
ll sum(ll p,ll c){
    if(c==0){
        return 1;
    }
    if(c&1){
        return (1+ksm(p,(c+1)>>1)%mod)*sum(p,(c-1)>>1)%mod;//如果为奇数
    }else{
        return (1+ksm(p,c>>1)%mod)*sum(p,(c>>1)-1)%mod+ksm(p,c)%mod;//如果为偶数
    }
}//进行操作
ll a,ans,b;

signed main(){
    scan(a);
    scan(b);
    ans=1;
    for(int i=2;i<=a;i++){
        int num=0;
        while(a%i==0){
            num++;
            a/=i;
        }
        if(num)
        ans=ans*sum(i,b*num)%mod;
    }
    if(a==0){
        puts("0");
    }else{
        printf("%lld
",ans%mod);  
    }
    
    return 0;
}
原文地址:https://www.cnblogs.com/xishirujin/p/11411077.html