题解——P1292 倒酒


前置知识——扩展欧几里得算法

用于求 \(ax+by=\gcd(a,b)\) 解。

求一组可行解

由欧几里得算法得,\(\gcd(a,b)=\gcd(b,a\bmod b)\)

所以列含参方程得:

\[\begin{cases} ax_1+by_1=\gcd(a,b)\\bx_2+(a\bmod b)y_2=\gcd(b,a \bmod b)\end{cases} \]

于是有:

\[ax_1+by_1=bx_2+(a\bmod b)y_2 \]

\[ax_1+by_1=bx_2+(a-\lfloor \dfrac{a}{b} \rfloor\times b)y_2 \]

\[ax_1+by_1=ay_2+b(x_2-\lfloor \dfrac{a}{b} \rfloor\ y_2) \]

所以:\(x_1=y_2,y_1=(x_2- \lfloor \frac{a}{b}\rfloor y_2)\),不断递归求解可以得到。

inline int exgcd(int a,int b,int &x,int &y){
    if(!b){
        x=1,y=0;
        return a;
    }
    int d=exgcd(b,a%b,x,y);
    int t=x;
    x=y,y=t-a/b*y;
    return d;
}

对于上述的方程是一定有解的,并且存在一组 \((x,y)\) 满足 \(|x|\le b,|y| \le a\),我们称其为裴蜀定理

求任意一组通解

设已经求出的可行解为 \((x_0,y_0)\),带入到方程中有:

\[\begin{cases} ax_0+by_0=\gcd(a,b)\\ax+by=\gcd(a,b)\end{cases} \]

联立并整理得:

\[a(x_0-x)=b(y-y_0) \]

\[\dfrac{a}{\gcd(a,b)}(x_0-x)=\dfrac{b}{\gcd(a,b)}(y-y_0) \]

容易发现这个等式左右两边的前一个因式是互质的,因此后一个因式与前一个因式是对应整除关系(根据唯一分解定理可以得到),设这个商为 \(k\),就有:

\[\begin{cases}x_0-x =\dfrac{b}{\gcd(a,b)}\times k\\\\y-y_0=\dfrac{a}{\gcd(a,b)}\times k\end{cases} \]

整理得到:\(x=x_0-\frac{b}{\gcd(a,b)}\times k,y=y_0+\frac{a}{\gcd(a,b)}\times k\),其中 \(k\in \mathbb{Z}\)

推广到不定方程

对于不定方程 \(ax+by=c\),解决方式如下:

求解 \(ax+by=gcd(a,b)\) 的一组解 \((x_0,y_0)\),同乘 \(\frac{c}{\gcd(a,b)}\),就能得到不定方程的一组可行解 \((x,y)=(x_0\times\frac{c}{\gcd(a,b)},y_0\times \frac{c}{\gcd(a,b)})\),而我们把它代入到通解的式子中,得到最终的结果:

\[\begin{cases} x=\dfrac{c}{\gcd(a,b)}\times x_0- \dfrac{b}{\gcd(a,b)}\times k \\\\ y=\dfrac{c}{\gcd(a,b)}\times y_0+ \dfrac{a}{\gcd(a,b)}\times k\end{cases} \]

特别地,\(x\) 的最小整数解为 \((x \bmod \frac{b}{\gcd(a,b)}+\frac{b}{\gcd(a,b)})\bmod\frac{b}{\gcd(a,b)}\)

分析

下面我们来看这道题,可以得到如下一个式子:

\[a(-x)+by=c \]

\(x_0=-x\),得到:

\[ax_0+by=c \]

当方程有解时,\(\gcd(a,b)\mid c\),所以 \(c\) 的最小值为 \(\gcd(a,b)\),第一问套模板即可解决。

第二问的解决相对抽象,可以结合图像来研究:

蓝色的直线表示 \(-5x+3y=1\),记为 \(l_1\);绿色的直线表示 \(5x+3y=1\),记为 \(l_2\),题目中的要求的是 \(l_1\) 的最小整数解,即点 \(B(x_1,y_1)\);我们所解的不定方程为 \(l_2\),可能得到的一组解为点 \(C\)

因为每一个 \(x\) 都满足 \(x=x_1-\frac{b}{\gcd(a,b)}\times k\ (k\in \mathbb{Z})\),所以我们可以找到 \(l_2\) 的最小正整数解 \((x_2,y_2)\),再减去一个 \(\frac{b}{\gcd(a,b)}\) 就得到了最大负整数解 \(A(x_3,y_3)\)(注意 \(0\) 的特判),可以发现:\(x1=-x3\ ,y1=y3\),按照如上思路运算即可。

实现

inline ll exgcd(ll a,ll b,ll &x,ll &y){
    if(!b){
        x=1,y=0;
        return a;
    }
    ll d=exgcd(b,a%b,x,y);
    ll t=x;
    x=y,y=t-a/b*y;
    return d;
}
int main(){
    ll a=read(),b=read();
    ll x=0,y=0;
    ll d=exgcd(a,b,x,y);
    printf("%lld\n",d);
    x=(x%(b/d)+(b/d))%(b/d);
    if(x) x-=(b/d);
    y=(d-a*x)/b;
    printf("%lld %lld\n",-x,y);
    return 0;
}