求A^B的所有约数之和mod一个数X (POJ 1845) 约数之和

根据唯一分解定理可以把A分解为质因数,表示为p1^c1 * p2^c2 * p3^c3 ...... * pn^cn

那么A^B表示为p1^(B*c1) * p2^(B*c2) * p3^(B*c3) ...... * pn^(B*cn)

A^B的所有约数表示为{p1^k1 * p2^k2 *  ... * pn^kn 其中0<= ki <= B * ci (1 <= i <=n)

所以根据成打分配律,A^B 的所有约数之和就是:

(1 + p1 + p1^2 + ...+ p1^(B*c1) ) * (1 + p2 + p2^2 + ...+ p2^(B*c2) ) * ... * (1 + pn + pn^2 + ...+ pn^(B*cn) )

上式中的每个括号内都是等比数列,如果使用等比数列求和公式,需要做除法。而答案还需要模一个数X,mod运算只对加 减 乘有分配律,不能对分子,分母分别取模后再做除法。

然而,可以使用分治法来进行 等比数列求和

sum(p,c)=1 + p + p^2 + ... +p^c = ?

若c为奇数:

sum(p,c) = (1 + p + ... + p^((c-1)/2) + (p^((c+1)/2) + ... + p^c)

= (1 + p + ... + p^((c-1)/2)  + p^((c+1)/2) * ( 1 + p + ... + p^((c-1)/2) 

= (1 + p^((c+1)/2) * sum(p, (c-1)/2);

若c为偶数

同理 sum(p,c) = (1 + p^(c/2)) * sum(p,c/2 - 1) + p^c

每次分治(即递归之后),问题的规模会缩小一半,配合快速幂即可在O(log c )的时间内求出等比数列的和

 

附代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define mod 9901
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;
}
ll sum( ll p, ll c)
{
    if(c==0)
    return 1;
    if(c&1)
    return ((1+ksm(p,(c+1)/2))*sum(p,(c-1)/2))%mod ;
    else
    return ((1+ksm(p,c/2))*sum(p,c/2-1)+ksm(p,c))%mod;
}
int main()
{
    ll a,b;
    ll ans=1;
    cin>>a>>b;
    for(ll i=2;i<=a;i++)
    {
        ll s=0;
        while(a%i==0)
        {
            s++;
            a/=i;
         } 
         ans=ans*sum(i,s*b)%mod;
    }
    if(a==0)
    cout<<"0"<<endl;
    else
    cout<<ans<<endl;
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值