关于exgcd
关于exgcd
对于二元一次不定方程\(ax+by=c\)
首先由裴蜀定理得,\(ax+by=gcd(a,b),\;gcd(a,b)\mid c\)
\[ax+by=gcd(a,b)\\
\]
\[
bx+(a\%b)y=gcd(b,a\%b) \\
\]
\[\because gcd(a,b)=gcd(b,a\%b) \\
\]
\[\therefore ax+by=bx+(a-\lfloor\frac{a}{b} \rfloor b)y \\
\]
\[\therefore ax+by=ay+(x-\lfloor\frac{a}{b} \rfloor y)b
\]
void exgcd(int a,int b,int &x,int &y){
if(b==0){
x=1;y=0;
return;
}
exgcd(b,a%b);
int tmp=x;
x=y;
y=tmp-a/b*y;
}
对于方程\(ax+by=gcd(a,b)\)两边同时乘以\(\frac{c}{gcd(a,b)}\),得到一组特解\(x_0 ,\; y_0\)
\[x_0=\frac{cx}{gcd(a,b)}
\]
\[y_0=\frac{cy}{gcd(a,b)}
\]
考虑推通解:
\[ax_0+by_0=c
\]
\[a(x_0+kb)+b(y_0-ka)=c
\]
令 \(d_x\) 为满足要求的 \(kb\) 的最小整数,\(d_y\) 为满足要求的 \(ka\) 的最小整数,因为 \(ka,kb\) 都是整数,当\(k=\frac{1}{gcd(a,b)}\)时
\[d_x=\frac {b}{gcd(a,b)}
\]
\[d_y=\frac {a}{gcd(a,b)}
\]
方程通解可以表示为:
\[x=x_0+kd_x
\]
\[y=y_0-kd_y
\]
当 \(x>0\) 时 \(k>\frac{-x_0}{d_x}\)
当 \(y>0\) 时 \(k>\frac{y_0}{d_y}\)
\(x,y\)同时取到正整数,当且仅当
\[\lceil\frac{-x_0+1}{d_x}\rceil\leq \lfloor\frac{y_0-1}{d_y} \rfloor
\]
当\(x\)取得最小值时,\(y\)取得最大值
void work(){
int a=read(),b=read(),c=read();
int x=0,y=0;
int g=exgcd(a,b,x,y);
if(c%g!=0){//根据裴蜀定理,g不整除必无解
printf("-1\n");
return;
}
x=x*c/g;y=y*c/g;//求出特解
int kx=b/g;
int ky=a/g;
int l=ceil(1.0*(-x+1)/kx);
int r=floor(1.0*(y-1)/ky);
if(l<=r){//两个都是正整数
int num=r-l+1;//解的个数
//当x取最小时,y对应取最大
int minx=x+l*kx,maxy=y-l*ky;
//当y取最小时,x对应取最大
int miny=y-r*ky,maxx=x+r*kx;
//printf("%lld %lld %lld\n",x,r,kx);
printf("%lld %lld %lld %lld %lld\n",num,minx,miny,maxx,maxy);
}
else{
int minx=x+l*kx;
int miny=y-r*ky;
printf("%lld %lld\n",minx,miny);
}
}
This is your dream.Anything you can dream,you can do it now.