1. 程式人生 > 實用技巧 >POJ 1845乘法逆元+約數和

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 ); }