几种求逆元的方法
题目背景 这是一道模板题 题目描述 给定n,p求1~n中所有整数在模p意义下的乘法逆元。 输入输出格式 输入格式: 一行n,p 输出格式: n行,第i行表示i在模p意义下的逆元。 输入输出样例 输入样例#1: 10 13 输出样例#1: 1 7 9 10 8 11 2 5 3 4 说明 1<=n<=3*10^6;n<p<20000528 输入保证 p 为质数。
一、扩展欧几里德 ax+by=gcd(a,b)的整数解
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,p; 4 void exgcd(int a,int b,int &x,int &y) 5 { 6 if(b==0){ 7 x=1;y=0;return; 8 } 9 exgcd(b,a%b,x,y); 10 swap(x,y); 11 y=y-a/b*x;//不可以写成y=y-a*x/b 12 }//x为a在mod p 意义下的逆元 13 int main() 14 { 15 scanf("%d%d",&n,&p); 16 for(int i=1,x,y;i<=n;++i) 17 { 18 exgcd(i,p,x,y); 19 while(x<0) x+=p; 20 printf("%d\n",x%p); 21 } 22 return 0; 23 }
二、费马小定理 要求P为质数
费马小定理
a^(p-1) ≡1 (mod p)
两边同除以a
a^(p-2) ≡1/a (mod p)
应该写a^(p-2) ≡ inv(a) (mod p)
所以inv(a) = a^(p-2) (mod p)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,p; 4 int ksm(int x,int y) 5 { 6 int ans=1; 7 while(y) 8 { 9 if(y&1) ans=1ll*ans*x%p; 10 y>>=1; 11 x=1ll*x*x%p; 12 } 13 return ans; 14 } 15 int main() 16 { 17 scanf("%d%d",&n,&p); 18 for(int i=1,x,y;i<=n;++i) 19 printf("%d\n",ksm(i,p-2)); 20 return 0; 21 }
三、线性递推逆元 要求P为质数
证明:
设x = p % a,y = p / a
于是有 x + y * a = p
(x + y * a) % p = 0
移项得 x % p = (-y) * a % p
x * inv(a) % p = (-y) % p
inv(a) = (p - y) * inv(x) % p
于是 inv(a) = (p - p / a) * inv(p % a) % p
然后一直递归到1为止,因为1的逆元就是1
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,p,inv[10000000]; 4 int main() 5 { 6 scanf("%d%d",&n,&p); 7 inv[1]=1; 8 for(int i=2;i<=n;++i) 9 inv[i]=(p-p/i)*1ll*inv[p%i]%p; 10 for(int i=1;i<=n;++i) printf("%d\n",inv[i]); 11 return 0; 12 }
四. 要求P为质数