# 逆元详解

69 篇文章 22 订阅

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

#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
typedef long long LL;
const int N = 10005;
const int MOD = 9901;

bool prime[N];
int p[N];
int cnt;

void isprime()
{
cnt = 0;
memset(prime,true,sizeof(prime));
for(int i=2; i<N; i++)
{
if(prime[i])
{
p[cnt++] = i;
for(int j=i+i; j<N; j+=i)
prime[j] = false;
}
}
}

LL power(LL a,LL b)
{
LL ans = 1;
a %= MOD;
while(b)
{
if(b & 1)
{
ans = ans * a % MOD;
b--;
}
b >>= 1;
a = a * a % MOD;
}
return ans;
}

LL sum(LL a,LL n)
{
if(n == 0) return 1;
LL t = sum(a,(n-1)/2);
if(n & 1)
{
LL cur = power(a,(n+1)/2);
t = (t + t % MOD * cur % MOD) % MOD;
}
else
{
LL cur = power(a,(n+1)/2);
t = (t + t % MOD * cur % MOD) % MOD;
t = (t + power(a,n)) % MOD;
}
return t;
}

void Solve(LL A,LL B)
{
LL ans = 1;
for(int i=0; p[i]*p[i] <= A; i++)
{
if(A % p[i] == 0)
{
int num = 0;
while(A % p[i] == 0)
{
num++;
A /= p[i];
}
ans *= sum(p[i],num*B) % MOD;
ans %= MOD;
}
}
if(A > 1)
{
ans *= sum(A,B) % MOD;
ans %= MOD;
}
cout<<ans<<endl;
}

int main()
{
LL A,B;
isprime();
while(cin>>A>>B)
Solve(A,B);
return 0;
}


#include <iostream>
#include <string.h>
#include <stdio.h>

using namespace std;
typedef long long LL;
const int N = 10005;
const int MOD = 9901;

bool prime[N];
int p[N];
int cnt;

void isprime()
{
cnt = 0;
memset(prime,true,sizeof(prime));
for(int i=2; i<N; i++)
{
if(prime[i])
{
p[cnt++] = i;
for(int j=i+i; j<N; j+=i)
prime[j] = false;
}
}
}

LL multi(LL a,LL b,LL m)
{
LL ans = 0;
a %= m;
while(b)
{
if(b & 1)
{
ans = (ans + a) % m;
b--;
}
b >>= 1;
a = (a + a) % m;
}
return ans;
}

LL quick_mod(LL a,LL b,LL m)
{
LL ans = 1;
a %= m;
while(b)
{
if(b & 1)
{
ans = multi(ans,a,m);
b--;
}
b >>= 1;
a = multi(a,a,m);
}
return ans;
}

void Solve(LL A,LL B)
{
LL ans = 1;
for(int i=0; p[i]*p[i] <= A; i++)
{
if(A % p[i] == 0)
{
int num = 0;
while(A % p[i] == 0)
{
num++;
A /= p[i];
}
LL M = (p[i] - 1) * MOD;
ans *= (quick_mod(p[i],num*B+1,M) + M - 1) / (p[i] - 1);
ans %= MOD;
}
}
if(A > 1)
{
LL M = MOD * (A - 1);
ans *= (quick_mod(A,B+1,M) + M - 1) / (A - 1);
ans %= MOD;
}
cout<<ans<<endl;
}

int main()
{
LL A,B;
isprime();
while(cin>>A>>B)
Solve(A,B);
return 0;
}


对于两个正整数，如果的倍数，那么中与互素的数的个数为

本结论是很好证明的，因为中与互素的个数为，又知道，所以

结论成立。那么对于本题，答案就是

其中为小于等于的所有素数，先筛选出来即可。由于最终答案对一个质数取模，所以要用逆元，这里

求逆元就有技巧了，用刚刚介绍的递推法预处理，否则会TLE的。

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <bitset>

using namespace std;
typedef long long LL;
const int N = 10000005;

bitset<N> prime;

void isprime()
{
prime.set();
for(int i=2; i<N; i++)
{
if(prime[i])
{
for(int j=i+i; j<N; j+=i)
prime[j] = false;
}
}
}

LL ans1[N],ans2[N];
LL inv[N];

int main()
{
isprime();
int MOD,m,n,T;
scanf("%d%d",&T,&MOD);
ans1[0] = 1;
for(int i=1; i<N; i++)
ans1[i] = ans1[i-1] * i % MOD;
inv[1] = 1;
for(int i=2;i<N;i++)
{
if(i >= MOD) break;
inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
}
ans2[1] = 1;
for(int i=2; i<N; i++)
{
if(prime[i])
{
ans2[i] = ans2[i-1] * (i - 1) % MOD;
ans2[i] = ans2[i] * inv[i % MOD] % MOD;
}
else
{
ans2[i] = ans2[i-1];
}
}
while(T--)
{
scanf("%d%d",&n,&m);
LL ans = ans1[n] * ans2[m] % MOD;
printf("%lld\n",ans);
}
return 0;
}


其中

所以只需要证明，而我们知道的逆元对应全部

中的所有数，既是单射也是满射。

所以进一步得到

证明完毕！

03-17
08-04 1335
11-18 1万+
10-06 1万+
02-25 2966

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、付费专栏及课程。