对于正整数a和m,如果有,那么把这个同余方程中的最小正整数解叫做a模m的逆元。
逆元一般用扩展欧几里得算法来求得,如果为素数,那么还可以根据费马小定理得到逆元为。
推导过程如下
求现在来看一个逆元最常见问题,求如下表达式的值(已知)
当然这个经典的问题有很多方法,最常见的就是扩展欧几里得,如果m是素数,还可以用费马小定理。
但是你会发现费马小定理和扩展欧几里得算法求逆元是有局限性的,它们都会要求与互素。实际上我们还有一
种通用的求逆元方法,适合所有情况。公式如下
现在我们来证明它,已知,证明步骤如下
下面来一个题目:
:很容易知道,先把分解得到,那么得到,那么
的所有因子和的表达式如下
第二种方法就是用等比数列求和公式,但是要用逆元。用如下公式即可
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
typedef long long LL;
const int N=10005;
const int MOD=29;
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 mul(LL m,LL k,LL p)
{
LL ans=0;
while(k)
{
if(k&1)
ans=(ans+m)%p;
m=m*2%p;
k>>=1;
}
return ans;
}
LL qmi(LL m,LL k,LL p)
{
LL res=1%p,t=m;
while(k)
{
if(k&1)
res=res*t%p;
t=t*t%p;
k>>=1;
}
return res;
}
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*=(qmi(p[i],num*B+1,M)+M-1)/(p[i]-1);
ans%=MOD;
}
}
if(A>1)
{
LL M=MOD*(A-1);
ans*=(qmi(A,B+1,M)+M-1)/(A-1);
ans%=MOD;
}
cout<<ans<<endl;
}
int main()
{
LL x;
ios::sync_with_stdio(false);
isprime();
while(cin>>x)
{
if(x==0)
break;
Solve(2004,x);
}
return 0;
}