POJ 1845 Sumdiv 【逆元】

题意:求A^B的所有因子之和

很容易知道,先把分解得到,那么得到,那么

的所有因子和的表达式如下

第一种做法是分治求等比数列的和

 用递归二分求等比数列1+pi+pi^2+pi^3+...+pi^n:

(1)若n为奇数,一共有偶数项,则:
      1 + p + p^2 + p^3 +...+ p^n

= (1+p^(n/2+1)) + p * (1+p^(n/2+1)) +...+ p^(n/2) * (1+p^(n/2+1))
      = (1 + p + p^2 +...+ p^(n/2)) * (1 + p^(n/2+1))

(2)若n为偶数,一共有奇数项,则:
      1 + p + p^2 + p^3 +...+ p^n

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

其他用到的知识是素数筛选以及快速幂,本博客都有相应知识或者百度也行

#include<stdio.h>
#include<string.h>
typedef long long ll;
const int mod=9901;
const int N=1e5+11;
int p[N],pr[N],cnt;
void init(){
    for(int i=2;i<N;i++){
        if(!p[i])    pr[++cnt]=i;
        for(int j=1;j<=cnt&&i*pr[j]<N;j++){
            p[i*pr[j]]=1;
            if(i%pr[j]==0)    break;
        }
    }
}
ll pow_m(ll a,ll b,ll m){
    ll ans=1;a%=m;
    while(b){
        if(b&1)
            ans=(ans*a)%m;
        a=(a*a)%m;
        b>>=1;
    }
    return ans;
}
ll sum(ll p,ll n){
    if(!n)    return 1;
    if(n&1){
        return (sum(p,n/2)*(1+pow_m(p,n/2+1,mod)))%mod;
    }
    else{
        return (sum(p,n/2-1)*(1+pow_m(p,n/2+1,mod))+pow_m(p,n/2,mod))%mod;
    }
}
int main(){
    ll a,b;
    init();
    while(~scanf("%lld%lld",&a,&b)){
        ll ans=1;
        for(int i=1;i<=cnt&&pr[i]*pr[i]<=a;i++){
            if(a%pr[i]==0){
                int num=0;
                while(a%pr[i]==0){
                    num++;
                    a/=pr[i];
                }
                ans=(ans*sum(pr[i],num*b))%mod;
            }
        }
        if(a>1){
            ans=(ans*sum(a,b))%mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

第二种方法就是用等比数列求和公式,但是要用逆元。用如下公式即可(已知a|b)

我们来证明它,已知,证明步骤如下

在快速幂时的乘法会爆longlong,所以用快速乘

#include<stdio.h>
#include<string.h>
typedef long long ll;
const int mod=9901;
const int N=1e5+11;
int p[N],pr[N],cnt;
void init(){
    for(int i=2;i<N;i++){
        if(!p[i])    pr[++cnt]=i;
        for(int j=1;j<=cnt&&i*pr[j]<N;j++){
            p[i*pr[j]]=1;
            if(i%pr[j]==0)    break;
        }
    }
}
ll mul(ll a,ll b,ll m){
    ll ans=0;a%=m;
    while(b){
        if(b&1)
            ans=(ans+a)%m;
        a=(a+a)%m;
        b>>=1;
    }
    return ans;
}
ll pow_m(ll a,ll b,ll m){
    ll ans=1;a%=m;
    while(b){
        if(b&1)
            ans=mul(ans,a,m);
        a=mul(a,a,m);
        b>>=1;
    }
    return ans;
}
int main(){
    ll a,b;
    init();
    while(~scanf("%lld%lld",&a,&b)){
        ll ans=1;
        for(int i=1;i<=cnt&&pr[i]*pr[i]<=a;i++){
            if(a%pr[i]==0){
                int num=0;
                while(a%pr[i]==0){
                    num++;
                    a/=pr[i];
                }
                ll M=(pr[i]-1)*mod;
                ans*=(pow_m(pr[i],num*b+1,M)+M-1)/(pr[i]-1);
                ans%=mod;
            }
        }
        if(a>1){
            ll M=(a-1)*mod;
            ans*=(pow_m(a,b+1,M)+M-1)/(a-1);
            ans%=mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

http://blog.csdn.net/lyy289065406/article/details/6648539

http://blog.csdn.net/acdreamers/article/details/8220787

时间: 2024-11-16 23:06:20

POJ 1845 Sumdiv 【逆元】的相关文章

POJ 1845 - Sumdiv ( 数论 + 唯一分解定理 + 快速幂取模 )

POJ 1845 - Sumdiv ( 数论 + 唯一分解定理 + 快速幂取模 ) 这是一道数论的好题,需要较好的数学基础 题意: 给定A,B,求A^B的所有因数的和,再MOD 9901 分析: 这里用到了数论当中相当一部分知识 a. 唯一分解定理 任何一个整数都可以分解为若干个素数的幂的乘积的形式 A = ( p1 ^ q1 + p2 ^ q2 + ..... + pn ^ qn ) p为素数 A^B = ( p1 ^ (q1*B) + p2 ^ (q2*B) + ..... + pn ^ (

poj 1845 Sumdiv (算术基本定理求一个数因子和)

求一个数的所有因子和可以用算术基本定理,下面是它的两个重要应用: (1)一个大于1的正整数N,如果它的标准分解式为: N=(P1^a1)*(P2^a2)......(Pn^an) 那么它的正因数个数为(1+a1)(1+a2).....(1+an). (2) 它的全体正因数之和为d(N)=(1+p1+...p1^an)(1+p2+...p2^a2)...(1+pn+...+pn^an) 和求一个数正因数个数的方法类似. 可以先打表出sqrt(n)以内的所有素数(当然也可以不打表),因为n的素因数中

POJ 1845 Sumdiv【同余模运算+递归求等比数列和+快速幂运算】

快速幂运算在第一次训练时候就已经遇到过,这里不赘述 同余模运算也很简单,这里也不说了,无非是(a+b)%m (a*b)%m 把m弄到里面变成(a%m+b%m)%m   (a%m*b%m)%m 今天学的最重要的还是递归二分求等比数列 题目大意是给出A和B,求A^B的约数和 解这个题,首先,对A进行素因子分解得到 (PI(pi^ai))^B 然后我们有约数和公式: 对A=PI(p1^k1) A的所有因子之和为S = (1+p1+p1^2+p1^3+...p1^k1) * (1+p2+p2^2+p2^

poj 1845 Sumdiv (同余定理,快速幂取余)

链接:poj 1845 题意:求A^B的所有因子的和对9901取余后的值 如:2^3=8,8的因子有 1,2,4,8,所有和为15,取余后也是15 应用定理主要有三个: (1)整数的唯一分解定理: 任意正整数都有且只有一种方式写出其素因子的乘积表达式. A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn)   其中pi均为素数 (2)约数和公式: 对于已经分解的整数A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^kn) 有A的所有因子之和为 S = 

POJ 1845 Sumdiv (快速分解因式+快速幂取模)

题目地址:POJ 1845 转载自:http://blog.csdn.net/lyy289065406/article/details/6648539 大致题意: 求A^B的所有约数(即因子)之和,并对其取模 9901再输出. 解题思路: 要求有较强 数学思维 的题 应用定理主要有三个: 要求有较强 数学思维 的题 应用定理主要有三个: (1)   整数的唯一分解定理: 任意正整数都有且只有一种方式写出其素因子的乘积表达式. A=(p1^k1)*(p2^k2)*(p3^k3)*....*(pn^

POJ 1845 Sumdiv(逆元的应用)

传送门 Sumdiv Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 19009 Accepted: 4773 Description 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 99

poj 1845 Sumdiv(求逆元)

Sumdiv Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 17590   Accepted: 4421 Description 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 99

POJ 1845 Sumdiv (数学,乘法逆元)

题意: 给出数字A和B,要求AB的所有因子(包括AB和1)之和 mod 9901 的结果. 思路: 即使知道公式也得推算一阵子. 很容易知道,先把分解得到,那么得到,那么的所有因子之和的表达式如下: 我们要做的就是计算出sum%9901的结果. 有两种方法: (1)直接用快速幂计算对上面sum的第一步推算求结果,在计算过程中顺便取模. (2)可以根据以下这条公式对上面sum的第二步推算求结果: 也是需要用到快速幂,过程也稍微复杂了些.注意 mb 可能会超过int. 以下是第二种方法的代码: 1

POJ 1845 Sumdiv

题目链接:http://poj.org/problem?id=1845 题意:给出A,B两个整数(0 <= A,B <= 50000000),输出A^B(A的B次,不是异或)的所有因子和模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)