约数之和

题意


假设现在有两个自然数 A 和 B,S 是 A^B 的所有约数之和。

请你求出 S mod 9901 的值是多少。

输入格式

在一行中输入用空格隔开的两个整数 A 和 B。

输出格式

输出一个整数,代表 S mod 9901 的值。

数据范围

0≤A,B≤5×10^7

输入样例:

2 3

输出样例:

15

注意: A 和 B 不会同时为 00。

分析


A的约数之和有公式,首先对A分解质因数得到 \(p_{1},p_{2},...,p_{n}\),并得到对应质因子的次数,然后\(ans=(p_{1}^{0}+...+p_{1}^{k_{1}})*....*(p_{n}^{0}+...+p_{n}^{k_{n}})\)

质因子分解的时间复杂度是\(O(n^{1/2})\),每个质因子的次数最多是30次(质因子最小是2,int范围内指数最高可达31),所以没什么问题。

但是本问题求得的\(A^B\)的约数之和,虽然质因子分解的复杂度一样,但每个质因子的次数最多是\(30*50000000=1.5*10^{9}\),直接计算会超时,需要优化时间复杂度。公式中的一项观察:\((p_{1}^{0}+...+p_{1}^{k_{1}})\)

  • 当某个质因子的次数是奇数时,包括0次,式子一共有偶数项,原问题=\((p_{1}^{0}+...+p_{1}^{k_{1}})\)=\((p_{1}^{0}+...+p_{1}^{\frac{k_{1}}{2}})\)+\((p_{1}^{\frac{k_{1}+1}{2}}+...+p_{1}^{k_{1}})\)=\((p_{1}^{0}+...+p_{1}^{\frac{k_{1}}{2}}) * (1+p_{1}^{\frac{k_{1}}{2}})\)
  • 当某个质因子的次数是偶数时,包括0次,式子一共有奇数项,原问题可以先用快速幂求出最后一项,剩余偶数项求和变成第一种情况

综上,若最高次数是k,我们可以通过分类讨论,将公式中的求和问题的时间复杂度降到 \(log(k)*log(k)\)(分治递归层数 * 快速幂时间复杂度),因此总的时间复杂度是\(O(n^{1/2} * log(k)^{2})\)

代码


#include<iostream>
using namespace std;

typedef long long ll;
const int mod=9901;

ll qmi(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 get(ll a,ll b)
{
    if(b==1)return 1;
    if(b&1)return (get(a,b-1)+qmi(a,b-1))%mod;
    return (1+qmi(a,b/2))*get(a,b/2)%mod;
}

int main()
{
    ll a,b;scanf("%lld%lld",&a,&b);
    ll ans=1;
    for(int i=2;i*i<=a;i++)
    {
        if(a%i==0)
        {
            int s=0;
            while(a%i==0)a/=i,s++;
            ans=ans*get(i,s*b+1)%mod;
        }
    }
    if(a>1)ans=ans*get(a,b+1)%mod;
    if(!a)ans=0;
    printf("%lld\n",ans);
    return 0;
}
posted @ 2021-03-13 15:07  冰糖ryj  阅读(106)  评论(0编辑  收藏  举报