Sumdiv 二分

Posted 偶尔爆零的蒟蒻

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Sumdiv 二分相关的知识,希望对你有一定的参考价值。

Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. Determine S modulo 9901 (the rest of the division of S by 9901).

Input
The only line contains the two natural numbers A and B, (0 <= A,B <= 50000000)separated by blanks.

Output
The only line of the output will contain S modulo 9901.

Sample Input
2 3
Sample Output
15

Hint
2^3 = 8.
The natural divisors of 8 are: 1,2,4,8. Their sum is 15.
15 modulo 9901 is 15 (that should be output).

题意

a b a^b ab的所有因子之和对 9901 9901 9901取模
题干很短,没想到背后原理一大堆。
感受到了数论的强大


定理参考


#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<stack>
#include<iomanip>
using namespace std;
#define ff first
#define ss second
#define ms(a,x) memset(a,x,sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
#define inf 0x3f3f3f3f  //10 6110 9567<2^30=10 7374 1824
#define iinf 0x7fffffff  //
const double eps=1e-6;
const int mod=9901;
const int MAX=1e5;
//快速幂取模
int power(int a,int b){
    int res=1;
    a%=mod;
    while(b){
        if(b&1)res=(res*a)%mod;
        b>>=1;
        a=(a*a)%mod;
    }
    return res;
}
int p[MAX+5];//素数数组
int cnt;
//欧拉筛
//原理:每个合数都存在一个最小质因子
void getPrime(){
    for(int i=2;i<=MAX;i++){
        if(!p[i])p[++cnt]=i;
        //          用之前产生的素数判断,逐渐扩展
        //          以最小质因子将合数划分
        for(int j=1;j<=cnt&&i*p[j]<=MAX;j++){
            p[i*p[j]]=1;
            if(i%p[j]==0)break;//最小质因子分解的界限
            //如果不中断,则i*p[j+1]被p[j+1]分解
            //设i=p[j]*k,表示i被最小质因子p[j]分解
            //i*p[j+1]=p[j]*k*p[j+1]
            //p[j+1]>p[j]
            //即用p[j+1]分解不是最小的质因子
            //会造成之后某个数重复判断,产生不必要的运算
        }
    }
}
//A=pi^ki*...*pj^kj   正整数A可被唯一分解为若干素数乘积,p为素数
//S(A)=(1+pi+...+pi^ki...)*...*(1+pj+...pj^kj...)   A的所有因子和
//A^B=pi^(ki*B)*...*pj^(kj*B)
//S(A^B)=(1+pi+pi^2...+pi^(ki*B))*...*(1+pj+pj^2+...+pj^(kj*B))
//si(A^B)=1+pi+pi^2+...+pi^(ki*B)    取其一部分
//n为偶数  (1+p+...+p^(n/2-1))*(1+p^(n/2+1))+p^(n/2)
//n为奇数  (1+p+...+p^(n/2))*(1+p^(n/2+1))     n/2会造成下取整  n/2+n/2+1=n

//求解因子和递推式的值
int sum(int p,int n){
    if(n==0)return 1;
    if(n&1) return (sum(p,n>>1)%mod*(1+power(p,(n>>1)+1)%mod))%mod;
    else return (sum(p,(n>>1)-1)*(1+power(p,(n>>1)+1))%mod+power(p,n>>1)%mod)%mod;
}
int main(){
    getPrime();
    int a,b;
    cin>>a>>b;
    int ans=1;
    //提取小于自身的因子,以及幂次
    for(int i=1;p[i]*p[i]<=a;i++){
        if(a%p[i]==0){
            int c=0;
            while(a%p[i]==0){
                c++;
                a/=p[i];
            }
            ans=(ans*sum(p[i],b*c))%mod;
        }
    }
    //剩下的a是质数
    if(a>1){
        ans=(ans*sum(a,b))%mod;
    }
    cout<<ans<<endl;
}

以上是关于Sumdiv 二分的主要内容,如果未能解决你的问题,请参考以下文章

Sumdiv 二分

POJ 1845 Sumdiv#质因数分解+二分

POJ 1845 Sumdiv (整数唯分+约数和公式+二分等比数列前n项和+同余)

Sumdiv|同余|约数|拓展欧几里得算法

一本通1633例 3Sumdiv

Sumdiv