求解逆元

蒙哥马利快速模:

这个算法的局限性很大,只有在模数p 是质数的情况下才可以使用。
首先我们设inv(a)是a的逆元那么根据定义, inv(a)∗a≡1(mod p)再根据费马小定理 a^(p−1)≡1%p , 易得 inv(a)∗a≡a^(p−1)(mod p) 
移项,得: inv(a)≡a^(p−2) 
于是我们得到了快速幂模算法的一个前提条件: inv(a)≡a^(p−2)(mod p)

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll; 
 4 const int mod=1e9+7;//质数 
 5 ll quick_pow(ll x,int p){
 6    ll res=1;
 7    while(p){
 8        if(p&1) res=(res*x)%mod;
 9        x=(x*x)%mod;
10        p>>=1;
11    }
12    return res;
13 }
14 ll inv(ll a){
15     ll inv_a=quick_pow(a,mod-2);
16     return inv_a;
17 }
18 int main(){
19     ll a;
20     cin>>a;
21     cout<<inv(a)<<endl;
22     return 0;
23 }

 

扩展欧几里得求逆元:

证明
考虑两个方程:
a*x1+b*y1=gcd(a,b),b*x2+(a%b)*y2=gcd(b,a%b)
由辗转相除法可得到gcd(a,b)= gcd(b,a%b)
从而得到a*x1+b*y1=b*x2+(a%b)*y2
即a*x1+b*y1=b*x2+(a-(a/b)*b)*y2=a*y2+b*(x2-(a/b)*y2)
所以x1=y2,y1=x2-(a/b)*y2.

当a与b互质时gcd(a,b)=1,即a*x+p*y=1.方程式对m取模,(a*x) mod (p)=1 mod p.

所以a的逆元为(x+p)%p.

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int p=9973;
 5 ll extgcd(ll a,ll b,ll &x,ll &y){
 6     if(b==0){
 7         x=1;
 8         y=0;
 9         return a;
10     }
11     ll gcd=extgcd(b,a%b,x,y);
12     ll t=x;
13     x=y;
14     y=t-(a/b)*y;
15     return gcd;
16 }
17 
18 int main(){
19     ll t,a,b,x,y;
20     cin>>t;
21     while(t--){
22         cin>>a>>b;
23         extgcd(b,p,x,y);
24         cout<<a*(x%p+p)%p<<endl;
25     }
26     return 0;
27 }

 

递推求解逆元:

求1 到n逆元表
这个比较适合逆元比较多的时候。比如数据范围在1e5内,随机的1e5内的个数的逆元,所以是所有逆元都得求反而会快点。
代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int N=1e6;
 5 ll inv[N];
 6 void xian_inv(int n,int p){
 7     inv[1]=1;
 8     for(int i=2;i<=10000;i++){
 9         inv[i]=(ll)(p-p/i)*inv[p%i]%p;
10     }
11 }
12 int main(){
13     int a;
14     xian_inv(10000,9973);
15     cin>>a;
16     cout<<inv[a]<<endl;
17     return 0;
18 }

 

posted @ 2019-10-04 19:59  yya雨  阅读(175)  评论(0编辑  收藏  举报