开头我们先讲解一下模运算的性质
一,模运算的性质
1.(a + b) % p=(a % p + b % p) %p
2.(a - b)%p=(a%p - b%p)%p
3.(a - b)%p=((a%p - b%p)%p+p)%p
4.(a * b)%p=(a%p * b%p)%p
二,除法的模运算
(a / b) % p=(a % p) / (b % p) ,如果我们保证可以整除,它是否成立呢?
取a=8,b=2,p=6; 左式=4,右式=1;也就是说 除法的模运算不一定成立。
那我们怎么算除法的模运算呢?我们就可以用逆元。
三,乘法逆元的定义
若ax≡1(mod p),则称 a 关于 1 模 p的乘法逆元为 x。
四,求乘法逆元
1.费马小定理求逆元
费马小定理是数论中一个定理:
假如 a 是 一个整数,m 是一个质数,那么
如果 m 是一个质数,而整数 a 不是 m 的倍数,那么
代码太简单就不给出了
2.扩展欧几里得算法
ax+by=1是扩展欧几里得的公式
而 ax≡1(mod p) 能推出ax+py=1
而x就是乘法逆元的解。
而扩展欧几里得的最小整数解x,是这样求的:
...
代码如下
void exgcd(int a,int b)
{
if(b==0)
{
x=1;
y=0;
return;
}
else
{
exgcd(b,a%b);
int t=y;
y=x-(a/b)*y;
x=t;
return;
}
}
int main()
{
cin>>a>>p;
exgcd(a,p);
cout<<(x%p+p)%p;
}
3.线性求逆元
inv[i] = ( p-p/i )*inv[ p%i ]%p;
代码如下
long long inv[N];
void get_inv( long long m )
{
inv[1]=1;
for(int i=2;i<=m-1;i++)
inv[i]=( m-m/i )*inv[ m%i ]%m;
}
五,乘法逆元的应用
有些题目我们要除以一个数,并且还要模一个数,我们就可以用乘法逆元,除以这个数等于乘这个数的乘法逆元。