【逆元】【数学】
逆元(inv)
1.什么是逆元
当求解公式:
设
则
即
逆元就是这样应用的;
2.求逆元的方法
(1).费马小定理
也写作
根据费马小定理,我们求解逆元的表达式
假如
题目中的数据范围
所以
复杂度
code:
const int mod=1000000007;
long long ksm(long long a,long long b)
{
if(b<0) return 0;
long long ret=1;
a%=mod;
while(b)
{
if(b&1) (ret*=a)%=mod;
b>>=1;
(a*=a)%=mod;
}
return ret;
}
long long inv(long long a)
{
return ksm(a,mod-2);
}
(2)扩展欧几里得算法求逆元
对于不完全为
求解 x,y的方法
百度百科-乘法逆元中有这样一个例子:
例如:4关于1模7的乘法逆元为多少?
4X≡1 mod 7
这个方程等价于求一个X和K,满足
4X=7K+1
其中X和K都是整数。
求x,k就是扩展欧几里得算法了吧~
可扩展欧几里得求逆元ax≡1(mod n)其中a,n互质;
复杂度:O(logn);
code:
#define ll long long
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if (b==0) {x=1,y=0;return a;}
else
{
ll r=exgcd(b,a%b,y,x);
y-=x*(a/b);
return r;
}
}
ll inv(ll a, ll n)
{
ll x,y;
exgcd(a,n,x,y);
x=(x%n+n)%n;
return x;
}
附P1082 同余方程 AC代码:
//另一种风格的exgcd,跟上面是等价的
#include <iostream>
#include <cstdio>
using namespace std;
int a,b,x,y,k;
void exgcd(int a,int b)
{
if(b==0)
{
x=1;
y=0;
return;
}
exgcd(b,a%b);
k=x;
x=y;
y=k-a/b*y;
return;
}
int main()
{
scanf("%d%d",&a,&b);
exgcd(a,b);
printf("%d",(x+b)%b);
}
(3)线性求逆元
已知一个质数
推导如下:
设
同除
再将
将
推导完毕
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3000010;
int inv[N]={0,1},n,p;
int main()
{
scanf("%d%d",&n,&p);
puts("1");
for(int i=2;i<=n;i++)
{
inv[i]=(ll)(p-p/i)*inv[p%i]%p;
printf("%d\n",inv[i]);
}
return 0;
}