Definition&Solution
在等式乘法中,有,同样在同余问题中,有ax≡1(mod p),其中p∈{素数},则称x为a在mod p域下的逆。
一、单个数求逆元
对于单个式子逆元的求法,显然可以通过解同余方程
ax≡1(mod p) ①
求得,注意p必须为素数,否则a在mod p域下无意义。即:可以使用解①式求得a在mod p域下的逆,但是不能使用其他求逆元的方法求解①式,因为①式不保证p属于{素数}。
二、线性求逆元
证明略。已知1的逆元是1,记inv[i]为i的逆元,有递推式:inv[i]=(-(p/i)*inv[p%i]%p+p)%p。
以后做数论 开long long! 开long long! 开long long! 开long long! 开long long! 开long long! 开long long!
即使结果在Int内,乘法处可能溢出。
三、线性求阶乘逆元。
即求(n!)内所有数字的逆元。时间复杂度O(n!) 即对于每一个数字处理时间为O(1)
使用方法一求出int[n!],然后有递推式:
inv[i]=inv[i+1]∗(i+1)。
证明不会略
Examples
1、单个数求逆元
lg P1082 同余方程
Description
求关于 xx 的同余方程 ax≡1(modb) 的最小正整数解。
Input
一行,包含两个正整数 a,b ,用一个空格隔开。
Output
一个正整数 x0 ,即最小正整数解。输入数据保证一定有解。
Sample Input
3 10
Sample Output
7
注意:本题可以在b为素数时求解a的逆,但是在b不为素数时的解不是a的逆元。仅仅是方程ax≡1(Mod b)的解。
Solution
由ax≡1(Mod b) ①
移项可得,ax-1≡0(Mod b) ②
根据同余的定义即得,求解②式即为求解不定方程ax-1=by,即求解ax-by=1的x的最小整数解。
求解后,注意若(a,b)<0,x取相反数,并不断+b成为正数
Code
#include<cstdio> long long int a,b,ans; inline void exgcd(long long int &x,long long int &y,long long int a,long long int b) { if(!b) { x=1;y=0;ans=a; return; } long long int x1,y1; exgcd(x1,y1,b,a%b); x=y1; y=x1-(a/b)*y1; return; } int main() { scanf("%lld%lld",&a,&b); b*=-1; long long int x,y; exgcd(x,y,a,b); b*=-1; if(ans<0) x=-x; while(x<=0) x+=b; printf("%lld\n",x); }
2、线性求区间逆元
lgP3811 【模板】乘法逆元
Description
给定n,p求1~n中所有整数在模p意义下的乘法逆元。
Input
一行n,p
Output
n行,第i行表示i在模p意义下的逆元。
Sample Input
10 13
Sample Output
1 7 9 10 8 11 2 5 3 4
Hint
1≤n≤3*1e6,n<p<20000528
输入保证 p 为质数。
Solution
板子题,套用做法2
Code
#include<cstdio> #define maxn 3000010 inline void qr(long long &x) { char ch=getchar();long long f=1; while(ch>'9'||ch<'0') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); x*=f; return; } inline long long max(long long a,long long b) {return a>b?a:b;} inline long long min(long long a,long long b) {return a<b?a:b;} inline void swap(long long &a,long long &b) { long long c=a;a=b;b=c;return; } long long n,a[maxn],p; void sf() { a[1]=1; printf("1\n"); for(long long i=2;i<=n;++i) { a[i]=(-(p/i)*a[p%i]%p+p)%p; printf("%lld\n",a[i]); } return; } int main() { qr(n);qr(p); sf(); return 0; }
Summary
以后做数论 开long long! 开long long! 开long long! 开long long! 开long long! 开long long! 开long long!