POJ 1845乘法逆元+约数和

乘法逆元计算等比数列的求和公式

题意

   给两个正整数A和B,计算AB的所有因子和的值对9901取模

思路

  约数和公式

  S=(1+p1+p1^2+.....+p1^k1)*(1+p2+p2^2+.....+p2^k2)*......*(1+pn+pn^2+pn^3+.....+pn^kn);  

  等比数列公式:(PB+c+1-1) / (p1-1)

  当模数mod为质数时,bmod-2逆元即为b的乘法逆元  

  当p-1不为mod的倍数时,逆元无效,此时p%mod = = 1,所以分母即为1 + 12 + .....+1B+c

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;

const int maxn = 2e5+10;
int m;
int p[100],c[100];
void divide(ll n)
{
    m = 0;
    for(int i = 2;i*i <= n;++i){
        if(n % i == 0){
            p[++m] = i;
            while(n%i==0){
                n/=i;
                c[m]++;
            }
        }
    }
    if(n > 1){
        p[++m] = n;
        c[m] = 1;
    }
}
ll multi(ll a,ll b,ll mod) {
    ll ret=0;
    while(b) {
        if(b&1)
            ret=(ret+a)%mod;
        a=(a<<1)%mod;
        b=b>>1;
    }
    return ret;
}
ll powmod(ll a,ll b,ll mod) {
    ll ret=1;
    while(b) {
        if(b&1)
            ret=multi(ret,a,mod);  //直接相乘的话可能会溢出
        a=multi(a,a,mod);
        b=b>>1;
    }
    return ret;
}
int main()
{
   // freopen("input.txt", "r", stdin);
    ll a,b;
    scanf("%lld%lld",&a,&b);
    divide(a);
   // cout<<m<<endl;
    int mod = 9901;
    ll ans = 1;
    for(int i = 1;i <= m;++i){
        ll nub = c[i]*b; 
        if((p[i]-1)%mod == 0){
            ans = ((nub+1)%mod * ans%mod)%mod;
            continue;
        }
        ll x = (powmod(p[i],nub+1,mod) - 1 + mod)%mod;
        ll y = powmod(p[i]-1,mod-2,mod);
        ans = ((x*y)%mod * ans)%mod;
    }
    printf("%lld\n",ans );
}

 

posted @ 2020-08-16 13:38  阿斯水生产线  阅读(134)  评论(0编辑  收藏  举报