扩展欧几里得
问:如何求得一组x,yx,yx,y,使得Ax+By=CAx+By=CAx+By=C成立。
假设上式成立,首先令g=gcd(A,B)g=gcd(A,B)g=gcd(A,B),那么上式就可以写成 k1gx+k2gy=Ck_1gx+k_2gy=Ck1gx+k2gy=C,化简得,g(k1x+k2y)=Cg(k_1x+k_2y)=Cg(k1x+k2y)=C,说明 C%gC\%gC%g=0 。所以Ax+By=CAx+By=CAx+By=C存在解得条件就是C%gC\%gC%g=0;反之,则不存在。
根据数论中相关定理,存在x,y,满足:Ax+By=gcd(A,B)Ax+By=gcd(A,B)Ax+By=gcd(A,B)。
怎么求一组解呢?
Ax1+By1=gcd(A,B)Ax_1+By_1=gcd(A,B)Ax1+By1=gcd(A,B)·················································································1
Bx2+(A%B)y2=gcd(B,A%B)Bx_2+(A\%B)y_2=gcd(B,A\%B)Bx2+(A%B)y2=gcd(B,A%B)
Bx2+(A−(A/B)∗B)y2=gcd(B,A%B)Bx_2+(A-(A/B)*B)y_2=gcd(B,A\%B)Bx2+(A−(A/B)∗B)y2=gcd(B,A%B)····················································2
1,2式等式左边相等:Ax1+By1=Bx2+(A−(A/B)∗B)y2Ax_1+By_1=Bx_2+(A-(A/B)*B)y_2Ax1+By1=Bx2+(A−(A/B)∗B)y2
整理一下:Ax1+By1=Ay2+B(x2−(A/B)y2)Ax_1+By_1=Ay_2+B(x_2-(A/B)y_2)Ax1+By1=Ay2+B(x2−(A/B)y2)
可以很明显看出:x1=y2,y1=x2−(A/B)y2x_1=y_2,y_1=x_2-(A/B)y_2x1=y2,y1=x2−(A/B)y2。下面给出代码
long long exgcd(long long a,long long b,long long &x,long long &y)
{
if(b==0){
x=1,y=0;//如果b==0,那么gcd(A,B)=A,那么x=1,y=0
return a;
}
long long ans=exgcd(b,a%b,x,y);
int temp=x;//下面这三句之所以要放在递归调用和return之间是因为要根据后面递归算出来的x,y值才能推出最开始的x,y
x=y;//(接上一行注释)也就是Ax+By=gcd(A,B)的解
y=temp-(a/b)*y;
return ans;
}
执行完这段程序后就可以得到一组特解x,y。那么怎么求通解呢,下面给出证明:
通解:x=x0+Bgcd(A,B)∗tx=x_0+\frac{B}{gcd(A,B)}*tx=x0+gcd(A,B)B∗t
y=y0−Agcd(A,B)∗ty=y_0-\frac{A}{gcd(A,B)}*ty=y0−gcd(A,B)A∗t
t为整数
就写道这吧。以后发现不足再改。
例题:
A line on the plane is described by an equation Ax + By + C = 0. You are to find any point on this line, whose coordinates are integer numbers from - 5·1018 to 5·1018 inclusive, or to find out that such points do not exist.
Input
The first line contains three integers A, B and C ( - 2·109 ≤ A, B, C ≤ 2·109) — corresponding coefficients of the line equation. It is guaranteed that A2 + B2 > 0.
Output
If the required point exists, output its coordinates, otherwise output -1.
Examples
Input
2 5 3
Output
6 -3
模板扩展欧几里得题:
代码:
#include<cstdio>
#include<set>
#include<map>
#include<string.h>
#include<string>
#include<vector>
#include<iostream>
#include<queue>
#include<algorithm>
typedef long long LL;
using namespace std;
const int maxn=1e6+5;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0){
x=1,y=0;
return a;
}
LL ans=exgcd(b,a%b,x,y);
LL temp=x;
x=y;
y=temp-(a/b)*y;
return ans;
}
int main()
{
LL a,b,c,x,y;
scanf("%lld%lld%lld",&a,&b,&c);
LL g=exgcd(a,b,x,y);
if((-c)%g!=0){
printf("-1\n");
}
else {
LL ansx=x*(-c/g);
LL ansy=y*(-c/g);
printf("%lld %lld\n",ansx,ansy);
}
return 0;
}
下面再补充一点求通解和最小正整数的解的代码
#include<cstdio>
#include<set>
#include<map>
#include<string.h>
#include<string>
#include<vector>
#include<iostream>
#include<queue>
#include<algorithm>
typedef long long LL;
using namespace std;
const int maxn=1e6+5;
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0){
x=1,y=0;
return a;
}
LL ans=exgcd(b,a%b,x,y);
LL temp=x;
x=y;
y=temp-(a/b)*y;
return ans;
}
int main()
{
LL a,b,c,x,y;
scanf("%lld%lld%lld",&a,&b,&c);
LL g=exgcd(a,b,x,y);
if((-c)%g!=0){
printf("-1\n");
}
else{
LL ansx=x*(-c/g);
LL ansy=y*(-c/g);
LL ta=b/g;
LL tb=a/g;
for(LL i=1;i<=100;i++){//枚举许多组解的过程
x=ansx+i*ta;
y=ansy-i*tb;
printf("%lld %lld\n",x,y);
cout<<(x*a+y*b+c==0)<<endl;
}
x=ansx+10*ta;//假设随意一组解,求x,y的最小正整数解
y=ansy-10*tb;
x=(x%ta-ta)%ta;
y=(y%tb+tb)%tb;//y的最小正整数解
x=(x%ta+ta)%ta;//x的最小正整数解
y=(y%tb-tb)%tb;
printf("%lld %lld\n",x,y);
}
return 0;
}