gcd & exgcd
gcd
我们规定:
[egin{equation}gcd(a,b)=a,b的最小公倍数
onumberend{equation}
]
显然我们有:
[egin{align}a&=k_1 imes gcd(a,b)
onumber\b&=k_2 imes gcd(a,b)
onumber\a\%b&=a-lfloorfrac{a}{b}
floor imes b
onumber\&=k_1 imes gcd(a,b)-lfloorfrac{a}{b}
floor imes k_2 imes gcd(a,b)
onumber\&=gcd(a,b) imes (k_1-k_2 imeslfloorfrac{a}{b}
floor)
onumberend{align}
]
显然(k_1,k_2,lfloorfrac{a}{b} floor)均为整数,且(gcd(k_1,k_2 imes lfloorfrac{a}{b} floor)=1)
(a\%b)也是(gcd(a,b))的倍数
那么我们就有:
[egin{equation} gcd(a,b)=gcd(b,a\%b)quad当且仅当a\%b=0时,gcd(a,b)=a
onumberend{equation}
]
下面是代码实现:
int gcd(int a,int b){
return b==0?a:gcd(b,a%b);
}
exgcd
我们要求解形如下面的方程的一组整数解:
[egin{align}ax+by=d
onumberend{align}
]
首先,这样的方程并不是一定有解的,我们有裴蜀定理:
[当且仅当gcd(a,b)|d时,ax+by=d有整数解 ]
所以如果方程有解,我们就可以操作一下它:
[egin{align}ax+by&=k imes gcd(a,b)
onumber\a(x_1 imes k)+b(y_1 imes k)&=k imes gcd(a,b)
onumber\ax_1+by_1&=gcd(a,b)
onumberend{align}
]
于是我们就把方程简化到上面的形式,它的一组解是((x_1,y_1))
那么原方程的一组解就是((x_1 imes k,y_1 imes k)),其中(k=frac{d}{gcd(a,b)})
接下来我们考虑怎么解简化后的方程:
[egin{align}ax+by&=gcd(a,b)
onumber\ax+by&=gcd(b,a\%b)
onumber\bx'+(a\%b)y' &=gcd(b,a\%b)
onumber\bx'+(a-lfloorfrac{a}{b}
floor imes b)y'&=ax+by
onumber\bx'+ay'-b imeslfloorfrac{a}{b}
floor imes y'&=ax+by
onumber\ay'+b(x'-lfloorfrac{a}{b}
floor imes y')&=ax+by
onumber\ay'+b(x'-lfloorfrac{a}{b}
floor imes y')&=gcd(b,a\%b)
onumberend{align}
]
我们可以根据最后一行式子递归下去求解
直到(a\%b=0)时,(gcd(a,b)=0),此时的一组解为(left{egin{align}x=1 onumber\y=0 onumberend{align} ight.)
这是最后一层的答案,我们考虑怎么通过这个得到上一层的答案
观察倒数第二行的式子,我们可以得到(left{egin{align}x&=y' onumber\y&=x'-lfloorfrac{a}{b} floor imes y' onumberend{align} ight.)
通过这个我们就可以一层一层向回推,得到最后的解了
代码:
#include<bitsstdc++.h>
using namespace std;
int gcd(int a,int b){
return b?a:gcd(b,a%b);
}
void exgcd(int a,int b,int &d,int &x,int &y){
if(b==0){
d=a;
x=1;
y=0;
}else{
exgcd(b,a%b,d,y,x);
y=y-a*x;
}
}
int main(){
int a,b,d;
scanf("%d%d%d",&a,&b,&d);
int tmp=gcd(a,b);
if(d%tmp)
printf("no solution!
");
else{
int x,y;
exgcd(a,b,tmp,x,y);
x=x*d/tmp;
y=y*d/tmp;
printf("%d %d
",x,y);
}
}