[数论]拓展欧几里得算法

欧几里得算法(辗转相除法)

用来求解最大公约数

1 int gcd(int a,int b){
2      return b ? gcd(b,a%b) : a;
3 }

在 #include<algorithm> 中也可以直接调用 __gcd(a,b)

 


 

拓展欧几里得算法

求解不定方程:

引理:存在 x , y 使得 gcd(a,b)=ax+b

 

 1 typedef long long ll;
 2 
 3 ll exgcd(ll a,ll b)
 4 {
 5     if(b){
 6         ll r=exgcd(b,a%b);
 7         ll k=x;
 8         x=y;
 9         y=k-a/b*y;
10         return r;
11     }
12     else{
13         x=1,y=0;
14         return a;
15     }
16 }

 


 

解线性同余方程

关于 x 的模方程 ax%b=c 的解,方程转换为 ax+by=c 其中 y 一般为非正整数,则问题变为用 exgcd 解不定方程

 


 

计算乘法逆元 

若 a*x≡1(mod b) ,且 a与 b互质,那么我们就能定义: x为 a的逆元

这就是利用拓欧求解线性同余方程 a*x≡c(mod b) 的 c=1 的情况。我们就可以转化为解 a*x + b*y = 1这个方程

 

 1 typedef long long ll;
 2 
 3 void exgcd(ll a,ll b)//扩展欧几里得算法求乘法逆元,x为a的逆元
 4 {
 5     if(!b){
 6         x=1,y=0;
 7         return;
 8     }
 9     exgcd(b,a%b);
10     ll k;
11     k=x;
12     x=y;
13     y=k-(a/b)*y;
14 }

 


 

一些例题

zoj 3609

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 ll gcd;
 5 
 6 ll exgcd(ll a,ll b,ll &x,ll &y)
 7 {
 8     if(b==0){
 9         x=1,y=0;
10         return a;
11     }
12     ll ans=exgcd(b,a%b,x,y);
13     ll temp=x;
14     x=y;
15     y=temp-a/b*y;
16     return ans;
17 }
18  
19 ll cal(ll a,ll b,ll c)
20 {
21     ll x,y;
22     gcd=exgcd(a,b,x,y);
23     ll ans=(x%b+b)%b;
24     if(!ans)
25         ans=b;
26     return ans;
27 }
28  
29 int main()
30 {
31     ll a,b,t;
32     cin>>t;
33     while(t--){
34         cin>>a>>b;
35         ll ans=cal(a,b,1);
36         if(gcd!=1)
37             cout<<"Not Exist\n";
38         else 
39             cout<<ans<<endl;
40     }
41     return 0;
42 }

 

zoj 3593

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 ll x,y;
 5 
 6 ll exgcd(int a,int b){
 7     if(b){
 8         ll n=exgcd(b,a%b);
 9         ll xt=x;
10         x=y,y=xt-a/b*y;
11         return n;
12     }
13     x=1,y=0;
14     return a;
15 }
16 
17 int main(){
18     ll n,m,t,a,b,c;
19     cin>>t;
20     while(t--){
21         cin>>n>>m>>a>>b;
22         c=n-m;
23         ll ans=exgcd(a,b);
24         if(c%ans!=0){
25             cout<<-1<<endl;
26             continue;
27         }
28         c/=ans,a/=ans,b/=ans;
29         x*=c,y*=c;
30         ll k=(y-x)/(a+b);
31         ans=10000000000ll;
32         for(ll i=k-1;i<k+2;i++){
33             ll xx;
34             ll x0=x+b*i,y0=y-a*i;
35             if(x0<=0&&y0>=0||y0<=0&&x0>=0)
36                 xx=abs(x0)+abs(y0);
37             else
38                 xx=max(abs(x0),abs(y0));
39             if(xx<ans)
40                 ans=xx;
41         }
42         cout<<ans<<endl;
43     }
44     return 0;
45 }

 

poj 1061

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 typedef long long ll;
 5 ll x,y;
 6 
 7 ll exgcd(ll a,ll b)
 8 {
 9     if(b){
10         ll r=exgcd(b,a%b);
11         ll k=x;
12         x=y;
13         y=k-a/b*y;
14         return r;
15     }
16     else{
17         x=1,y=0;
18         return a;
19     }
20 }
21 
22 int main()
23 {
24     ll p,q,m,n,l;
25     scanf("%lld%lld%lld%lld%lld",&p,&q,&m,&n,&l);
26         ll a=n-m,b=l,c=p-q;
27         ll ans=exgcd(a,b);
28         if(c%ans)
29             printf("Impossible\n");
30         else{
31             ll k=c/ans,t=b/ans;
32             x*=k;
33             if(t<0)
34                 t=-t;
35             x=(x%t+t)%t;
36             cout<<x<<endl;
37         }
38     return 0;
39 }

 

hdu 1576

 1 #include <iostream>
 2 #include <cstdio>
 3 using namespace std;
 4 typedef long long ll;
 5 ll x,y;
 6 
 7 ll exgcd(ll a,ll b)
 8 {
 9     if(b){
10         ll r=exgcd(b,a%b);
11         ll k=x;
12         x=y;
13         y=k-a/b*y;
14         return r;
15     }
16     else{
17         x=1,y=0;
18         return a;
19     }
20 }
21 
22 int main()
23 {
24     ll p,q,m,n,l;
25     scanf("%lld%lld%lld%lld%lld",&p,&q,&m,&n,&l);
26         ll a=n-m,b=l,c=p-q;
27         ll ans=exgcd(a,b);
28         if(c%ans)
29             printf("Impossible\n");
30         else{
31             ll k=c/ans,t=b/ans;
32             x*=k;
33             if(t<0)
34                 t=-t;
35             x=(x%t+t)%t;
36             cout<<x<<endl;
37         }
38     return 0;
39 }

 

上一篇:2019牛客暑期多校训练营(第十场)D题(拓展中国剩余定理)


下一篇:数论基础