TZOJ: 5845:A^B的约数和(二分法求等比数列前n项和)

题面

TZOJ: 5845:A^B的约数和(二分法求等比数列前n项和)_第1张图片

第一步:对A进行质因数分解,并将其存入map中

map maps;
void get_prime(int n){
    for(int i=2;i<=n;i++){
        if(n%i==0){
            int ans=0;
            while(n%i==0){
                n=n/i;
                ans++;
            }
            maps[i]+=ans;
        }
    }
    if(n>1) maps[n]++;
}

第二步:

当 A= p1^a1 + p2^a2 + p3^a3....pm^am;

那么 A^b= p1^(a1 * b) + p2^(a2 * b) + ... + pm^(am * b);

那么约数之和就等于(1 + p1 + p1^1 + p1^2 +...+ p1^(a1 * b))*(1 + p2 + ....);

那么就变成了求以p1(p2,p3...)为公比的等比数列前n项和;

假如项数为n:

当n==0时,根据题意要输出1,如果首项为p,那么当n==0时应当输出0;

当n=奇数,会有偶数项,我们把1和p^(n/2+1)放在一起 p和p^(n/2+1+1)放在一起,以此类推
最后提公因式,得到【1+p^(n/2+1)】*【1+p+p^2+p^3+....+p^(n/2-1)】右边恰为原式的一半

当n=偶数,可以由奇数的情况推过来.若用sum(p,k)表示公比为p的前k+1项和(首项为1),那么

sum(p,k)=p*sum(p,k-1)+1;
因此二分递归则可以得到答案
 

#include 
using namespace std;
typedef long long LL;
const int mod=9901;
map maps;
void get_prime(int n){
    for(int i=2;i<=n;i++){
        if(n%i==0){
            int ans=0;
            while(n%i==0){
                n=n/i;
                ans++;
            }
            maps[i]+=ans;
        }
    }
    if(n>1) maps[n]++;
}
LL qpow(LL a,LL k){
    if(k==0) return 1;
    LL t=qpow(a,k/2);
    if(k%2==0) return t*t%mod;
    return t*t%mod*a%mod;
}
LL sum(LL p,LL k){
    if(k==0) return 1;
    if(k%2==0) return (p%mod*sum(p,k-1)+1)%mod;
    return (1+qpow(p,k/2+1))*sum(p,k/2)%mod;
}
int main(){
    LL a,b;
    cin>>a>>b;
    get_prime(a);
    LL res=1;
    for(map::iterator it=maps.begin();it!=maps.end();it++){
        LL x=it->first,y=it->second;
        res=res*sum(x,y*b)%mod;
    }
    cout<

你可能感兴趣的:(数学,算法)