一、费马小定理求法
费马小定理:对于a是一个整数,p是一个质数,有 a^p - a =k*p
即有 a^p ≡ a(mod p)
即有 a^(p-1) mod p =1 mod p
逆元:a关于p的逆元即a关于p取模的倒数 即 a^-1 mod p就是我们想要求的
所以 由费马小定理两边同乘 a^-1
得 a^(p-2) mod p = a的-1次方 mod p,因此a ^ (p-2) mod p就是所求的a关于p的逆元
运用快速幂求解
快速幂基本思路:对于a的b次方,我们都可以把b分为几个2的次方相乘的形式,如2^5= 2 ^(2 ^2) * 2 ^(2 ^0)。
ll pow_mod(ll a,ll b,ll p)
{
ll ret=1;
while(b) //若求2的五次方,则将b看乘是个二进制数,即101.
{
if(b&1) ret=ret*a%p;//对于该二进制数,若最后一位是1,则表示此时的a是分割b的其中一个2的次方
a=a*a%p;//不管最后一位是否为1,都要执行此步,按照二进制数规则2的次方
b=b>>1;//然后再看下一位数。
}
return ret;
}
主函数中只需要
pow_mod(a,p-2,p);
二、扩展欧几里得求法
int exgcd(int a,int b,int &x,int &y)
{
if(!b)
{
x=1;
y=0;
return a;
}
int d=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-(a/b)*y;
return d;
}
int inv(int a,int p)
{
int x,y;
int d=exgcd(a,p,x,y);
if(d==1)
return (x%p+x)%p;
else
return -1;
}
主函数中只需要写
inv(a,b);//即得到a关于b的逆元
三、求递推记忆求多个逆元
如求1~n中所有的数关于m的逆元
long long inv[maxn];
void init(long long n,long long p)
{
inv[1]=1;
for(int i=2;i<=n;i++)
{
inv[i]=(long long)((p-p/i)*inv[p%i]%p);
}
}
主函数中只需写
init(n,m);