【Luogu】P1593因子和(唯一分解定理,约数和公式)

题目链接

首先介绍两个定理。

整数唯一分解定理:任意正整数都有且只有一种方式写出素数因子的乘积表达式。

(A=(p1k1 p2k2 ...... pnkn )

求这些因子的代码如下

for(int i=2;i*i<=a;++i){
        if(!(a%i)){
            prime[++num]=i;
            while(!(a%i)){
                a/=i;
                sum[num]++;
            }
        }
    }
    if(a!=1){
        prime[++num]=a;
        sum[num]=1;
    }
唯一分解定理

约数和公式:对于已经分解的整数A,有A的所有因子和为

( S= (1+p1+p12+p13+......+p1k1) (1+p2+p22+p23+......+p2k2)........(1+pn+pn2+pn3+......+pnkn) )

所以局势明朗。用快速幂求出p的k*b次方,然后递归求和。代码如下

long long Sum(long long p,long long n){
    if(n==0)    return 1;
    if(n&1)    return (Sum(p,n>>1)*(1+Pow(p,(n>>1)+1)))%mod;
    return     (Sum(p,(n>>1)-1)*(1+Pow(p,(n>>1)+1))+Pow(p,n>>1))%mod;
}

解题代码如下

#include<cstdio>
#include<cctype>
#define mod 9901
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

int prime[10000];
int sum[10000];
int num;

long long Pow(long long n,long long i){
    if(i==0)    return 1;
    if(i==1)    return n%mod;
    long long ret=Pow(n,i>>1);
    if(i&1)    return (((ret*ret)%mod)*n)%mod;
    return (ret*ret)%mod;
}

long long Sum(long long p,long long n){
    if(n==0)    return 1;
    if(n&1)    return (Sum(p,n>>1)*(1+Pow(p,(n>>1)+1)))%mod;
    return     (Sum(p,(n>>1)-1)*(1+Pow(p,(n>>1)+1))+Pow(p,n>>1))%mod;
}

int main(){
    long long a=read(),b=read();
    for(int i=2;i*i<=a;++i){
        if(!(a%i)){
            prime[++num]=i;
            while(!(a%i)){
                a/=i;
                sum[num]++;
            }
        }
    }
    if(a!=1){
        prime[++num]=a;
        sum[num]=1;
    }
    int ans=1;
    for(int i=1;i<=num;++i)
        ans=(ans*Sum(prime[i],sum[i]*b)%mod)%mod;
    printf("%d",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/7483285.html