鼓起了很大勇气决定发表这篇文章但是没想到写完一遍忘保存gg了 (捂脸哭) anyway 现在我还是重新开始了
扩展欧几里得这个算法是计算ax+by=c 关于(x,y)的整数解的
首先 如果(x,y)有解 必须是当且仅当c是gcd(a,b)的倍数
证明:一、:如果有整数解,则c是p的倍数。
令p=gcd(a,b)
a=aa*p
b=bb*p
则gcd(aa,bb)=1
c=ax+by=p*(aa*x+bb*y) 那么c显然是p的倍数
二、如果c是p的倍数,则ax+by=c有整数解。(在证明这个的同时也是拓展欧几里得的过程)
①用欧几里得算法计算gcd(a,b)时最后调用的一定是gcd(p,0),对于(p,0)来说是存在对应的(x,y)使得p*x+0*y=c成立的,只要让x=c/p,y取任意数即可;
②欧几里得算法的核心是把(a,b)辗转为(b,a mod b),假设(b,a mod b)存在对应的(x1,y1)使得 b*x1+(a mod b)*y1=c,根据:
ax+by=b*x1+(a mod b)*y1
=b*x1+(a-[a/b]*b)*y1
=a*y1+b*(x1-[a/b]*y1)
x=y1,y=x1-[a/b]*y1
即存在整数解x,y满足ax+by=c
x=y1 y=x1-[a/b]*y1
我们得出这个结论后 只要在gcd递归的过程中用 上一次递归出来的x1,y1 来替换现在的
x=y1 y=x1-[a/b]*y1
void gcd(long long a,long long b)
{long long o;
if (b==0)
{ x=c/a;y=0;
return;
}
gcd(b,a%b);
o=x;x=y;y=o-a/b*y;
}
ax+by=c有无穷组解,扩展欧几里得算法计算出来的解是其中一个特解(x0,y0),我们完全可以在递归出口处任意修改y的值来获得其他特解。
假如我们把方程的所有解按x的值从小到大排序,特解(x0,y0)的下一组解可以表示为(x0+d1,y0+d2),其中d1是符合条件的最小的正整数,则满足:a*(x0+d1)+b*(y0,d2)=c,由于ax+by=c,所以a*d1+b*d2=0。即:
(https://img-blog.csdn.net/20161101155044390)
所以如果要最小正整数解
我们只需要把求出来的特解 x x=(x+mod)%mod就行了 mod=b/gcd(a,b)
pku 1061青蛙的约会
题意:有两只青蛙,一只在坐标x,另一直在坐标y,青蛙x一次跳跃可以前进m单位距离,青蛙y一次跳跃可以前进n单位的距离,两青蛙都在同一纬度,该纬度长度为L。两只青蛙同方向同时跳,问最少跳多少次,它们才可以相遇,如果不能相遇,输出impossible
假设跳了T次以后,青蛙1的坐标x+m*T,青蛙2的坐标y+n*T。它们能够相遇的情况为
(x+m*T)-(y+n*T)=P*L
(n-m)*T+P*L=x-y
设a=(n-m),b=L,c=x-y,T=x,P=y
那么 ax+by=c
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
long long x,y,u,v,n,m,l,g;
void gcd(long long a,long long b)
{long long o;
if (b==0)
{ x=(u-v)/a;y=0;
g=a;return;
}
gcd(b,a%b);
o=x;x=y;y=o-a/b*y;
}
int main()
{scanf("%lld%lld%lld%lld%lld",&u,&v,&m,&n,&l);
gcd(n-m,l);
l=l/g;
if ((u-v)%g!=0) printf("Impossible");
else printf("%lld",(x%l+l)%l);
}
NOIP2012 同余方程
求关于x的同余方程ax ≡ 1 (mod b)的最小正整数解。
ax mod b=1 mod b
ax+by=1 这里c=1
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
int x,y,a,b;
void gcd(int a,int b)
{int t;
if (b==0)
{ x=1;
y=0;
return;
}
gcd(b,a%b);
t=x;x=y;y=t-(a/b)*y;
}
int main()
{ scanf("%d%d",&a,&b);
gcd(a,b);
printf("%d",(x%b+b)%b);
}