浅谈扩展欧几里得[exgcd] By cellur925

关于扩展欧几里得从寒假时就很迷,题解过了同余方程,但是原理并不理解。

今天终于把坑填上了qwq。

由于本人太菜,不会用markdown,所以这篇总结是手写的(什么)。(字丑不要嫌弃嘛)

 

********Update9.28**********

 刚刚我们求出的是一组特值,那么如何求通值?

约定:设x0,y0为一组特解,t为任意整数,设a>b(不行再交换)

那么有  x=x0+b/gcd*t
     y=y0-a/gcd*t

*******************************

奉上三道例题:

Ep1 青蛙的约会 Luogu P1516

花姐姐(@皎月半洒花)说的太棒了,我都不忍再去添加什么。

奉上链接,侵删!

Code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 
 5 using namespace std;
 6 typedef long long ll;
 7 
 8 ll xx,yy,ans;
 9 ll x,y,m,n,t;
10 
11 ll exgcd(ll a,ll b,ll &xx,ll &yy)
12 {
13     if(!b)
14     {
15         xx=1;
16         yy=0;
17         return a;
18     }
19     ans=exgcd(b,a%b,xx,yy);
20     ll tmp=xx;
21     xx=yy;
22     yy=tmp-a/b*yy;
23     return ans;
24 }
25 
26 int main()
27 {
28     scanf("%lld%lld%lld%lld%lld",&x,&y,&m,&n,&t);
29     ll a=n-m,z=x-y;
30     if(a<0) a=-a,z=-z;
31     exgcd(a,t,xx,yy);
32     if(z%ans) printf("Impossible");
33     else printf("%lld",((xx*(z/ans))%(t/ans)+(t/ans))%(t/ans));
34     return 0;
35 }
View Code

注意体会同余方程转线性方程的思想与做法!

 

Ep2 倒酒 Luogu P1292

容易看出,得到酒的最小体积是gcd(a,b),这种思想在我以前写的“瓶子和燃料”一题中有所体现。模拟一下就可以发现,之后的次数就是ax+by=gcd(a,b)的一组最小解。

套exgcd板子就行了,但是注意取最小值的那一部分,其实感觉每个题取最小值的方法都各有千秋,都要独立思考,这是关键。

一个不错的题解,侵删。

Code

 1 #include<cstdio>
 2 #include<algorithm>
 3 
 4 using namespace std;
 5 typedef long long ll ;
 6 
 7 ll a,b,x,y,ans;
 8 
 9 ll exgcd(ll a,ll b,ll &x,ll &y)
10 {
11     if(!b)
12     {
13         x=1;y=0;
14         return a;
15     }
16     ll d=exgcd(b,a%b,x,y);
17     ll tmp=x;
18     x=y;
19     y=tmp-y*(a/b);
20     return d;
21 }
22 
23 int main()
24 {
25     scanf("%lld%lld",&a,&b);
26     ans=exgcd(a,b,x,y);
27     printf("%lld\n",ans);
28     a/=ans,b/=ans;
29     while(x>0) x-=b,y+=a;
30     while(x+b<=0&&y>=a) x+=b,y-=a;
31     printf("%lld %lld",-x,y);
32     return 0;
33 }
View Code

ps:while(x>0)那里如果写成while(x)竟会死循环,还是老实一点吧。

 

Ep3 同余方程 Luogu P1082

把同余方程转一下。直接套exgcd模板,取最小值部分,lyd老师的讲解:

“用exgcd求出一组特解x0,y0,则x0就是原方程的一个解,通解为所有膜b与x0同余的整数,通过取模操作把解的范围移动到1~b”之间,就得到了最小正整数解。

Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 using namespace std;
 6 int exgcd(int a,int b,int &x,int &y)
 7 {
 8     if(b==0)  
 9     {  
10           x=1;  
11           y=0;  
12           return a;  
13     }  
14     int r=exgcd(b,a%b,x,y);  
15     int t=x;  
16     x=y;  
17     y=t-a/b*y;  
18     return r;  
19 
20 }
21 int main()
22 {
23     int a,b,x,y;
24     scanf("%d%d",&a,&b);
25     exgcd(a,b,x,y);
26     cout<<(x+b)%b;
27     return 0;
28 } 
View Code

 

posted @ 2018-08-21 22:15  cellur925&Chemist  阅读(235)  评论(0编辑  收藏  举报