AcWing 97.约数之和 (约数定理)

题目:约数之和

题意:

求 A^B的约数之和对9901取模的答案,A,B在[0, 5 ∗ 1 0 7 5*10^7 5107]中,A,B不能同时为0

题解:

约数之和定理:

证明:
首先我们可知一个数 A 可以拆分为: A = p 1 a ∗ p 2 b . . . . . ∗ p n c A=p1^a*p2^b.....*pn^c A=p1ap2b.....pnc ,( p p p 代表质数)
A A A 的约数个数为 ( a + 1 ) ∗ ( b + 1 ) . . . . ∗ ( c + 1 ) (a+1)*(b+1)....*(c+1) (a+1)(b+1)....(c+1)
由乘法分配律: s u m ( A ) = ( p 1 0 + p 1 1 + . . . . . p 1 a ) ∗ ( p 2 0 + p 2 1 + . . . . . p 2 b ) . . . . . . . ∗ ( p n 0 + p n 1 + . . . . . p n c ) sum(A)=(p1^0+p1^1+.....p1^a)*(p2^0+p2^1+.....p2^b).......*(pn^0+pn^1+.....pn^c) sum(A)=(p10+p11+.....p1a)(p20+p21+.....p2b).......(pn0+pn1+.....pnc)

优化:
对于 A A A 的一个 p p p 的所有约数和,我们可以用递归来实现,但是时间复杂度太高,所以我们需要对递归进行优化,使其变成 O ( l o g n ) O(logn) O(logn)
当k是奇数:
s u m ( p , k ) = ( p 0 + p 1 + . . . . . p k ) = ( p 0 + . . . . p k / 2 ) + ( p k / 2 + 1 . . . . . + p k ) = ( p 0 + . . . . p k / 2 ) + p k / 2 + 1 ∗ ( p 0 + . . . . p k / 2 ) = ( 1 + p k / 2 + 1 ) ∗ s u m ( p , k / 2 ) sum(p,k)=(p^0+p^1+.....p^k)=(p^0+....p^{k/2})+(p^{k/2+1}.....+p^k)=(p^0+....p^ {k/2})+p^{k/2+1}*(p^0+....p^{k/2})=(1+p^{k/2+1})*sum(p,k/2) sum(p,k)=(p0+p1+.....pk)=(p0+....pk/2)+(pk/2+1.....+pk)=(p0+....pk/2)+pk/2+1(p0+....pk/2)=(1+pk/2+1)sum(p,k/2)

当k是偶数时,我们可以按照一般的递归方式写即可,时间复杂度依然为 O ( l o g n ) O(logn) O(logn)

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define mod 9901
const int maxn=1e5+5;
ll ksm(ll a,ll b)
{
    ll res=1;
    a%=mod;
    while(b)
    {
        if(b&1)
            res=(a%mod)*(res%mod)%mod;
        a=(a%mod)*(a%mod)%mod;
        b>>=1;
    }
    return res%mod;
}
ll sum(ll a,ll b)
{
    if(b==0)
        return 1;
    if(b&1)
        return (1+ksm(a,(b>>1)+1))*sum(a,b>>1)%mod;
    else
        return (ksm(a,b)+sum(a,b-1)%mod)%mod;
}
void solv(ll x,ll b)
{
    ll res=1;
    for(int i=2;i<=x;i++)
    {
        int s=0;
        while(x%i==0)
        {
            s++;
            x/=i;
        }
        if(s)
            res=(res%mod)*(sum(i,s*b)%mod)%mod;
    }
    cout<<res%mod<<endl;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    ll a,b;
    cin>>a>>b;
    if(a==0)
        cout<<0<<endl;
    else
    solv(a,b);
}

  

你可能感兴趣的:(ACM刷题题解)