关于扩展欧几里得从寒假时就很迷,抄题解过了同余方程,但是原理并不理解。
今天终于把坑填上了qwq。
由于本人太菜,不会用markdown,所以这篇总结是手写的(什么)。(字丑不要嫌弃嘛)
********Update9.28**********
刚刚我们求出的是一组特值,那么如何求通值?
约定:设x0,y0为一组特解,t为任意整数,设a>b(不行再交换)
那么有 x=x0+b/gcd*t
y=y0-a/gcd*t
*******************************
奉上三道例题:
Ep1 青蛙的约会 Luogu P1516
花姐姐(@皎月半洒花)说的太棒了,我都不忍再去添加什么。
奉上链接,侵删!
Code
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
注意体会同余方程转线性方程的思想与做法!
Ep2 倒酒 Luogu P1292
容易看出,得到酒的最小体积是gcd(a,b),这种思想在我以前写的“瓶子和燃料”一题中有所体现。模拟一下就可以发现,之后的次数就是ax+by=gcd(a,b)的一组最小解。
套exgcd板子就行了,但是注意取最小值的那一部分,其实感觉每个题取最小值的方法都各有千秋,都要独立思考,这是关键。
一个不错的题解,侵删。
Code
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }
ps:while(x>0)那里如果写成while(x)竟会死循环,还是老实一点吧。
Ep3 同余方程 Luogu P1082
把同余方程转一下。直接套exgcd模板,取最小值部分,lyd老师的讲解:
“用exgcd求出一组特解x0,y0,则x0就是原方程的一个解,通解为所有膜b与x0同余的整数,通过取模操作把解的范围移动到1~b”之间,就得到了最小正整数解。”
Code
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
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 }