题意:的最小非负整数解

知识点: 裴蜀定理,扩展欧几里得算法

思路: 我们先简化符号为ax+by=L,根据裴蜀定理得知ax+by=gcd(a,b)一定有x,y不全为0的整数解

所以如果L不是gcd(a,b)的整数倍则一定无解。

接着根据辗转相除法我们得知gcd(a,b)=gcd(b,a%b)

而a%b我们也可以表示为(这个符号的意思是向下取整)

然后这个式子就可以像之前的辗转相除法一样一直到b=0时

此时我们可以设然后求出的值,(y'可以设任意值,为了方便考虑设y'=0是个不错的选择)接着我们在倒推回去。

所以上一步的(x,y)就等于

因此只要知道了下一层的x'和y'就能推出上一层的x,y最终得到我们的原式ax+by=L 的一组解

接着根据通解公式

是一组特解,t是任意常数。

由此得出x和y的函数求交点,接着求满足x>=0和y>=0的界限t。如果是小数去周围两个整数点做比较即可。

求解交点:

接着我们代入公式求得t,将t_max,t_min,t+1,t,t-1。五个数进行比较输出最优解即可。(因为途中运算会超出longlong,所以要把类型换成__int128。)

这里在举个例子说明:

假设a=1,b=1,L=2
则我们求出的ax+by=gcd(a,b)的一组特解应该是
x0=0,y0=1。接着x,y乘上L/gcd(a,b)得到ax+by=L的一组特解
x0=0,y0=2。
我们根据公式代入得
(-2*1)/2=-1
代入通解公式得到
x=0-(1*-1)=1
y=2+(1*-1)=1
直接得到整数最优解。x=1,y=1。

第二个例子
假设a=6,b=4,L=14 
解出特解x0=1,y0=-1乘上L/gcd(a,b)变成x0=7,y0=-7
代入t的公式得
(14*2)/10=2.8
将t=3和t=2代入通解得
x1=7-(2*3)=1
y1=-7+(3*3)=2
x2=7-(2*2)=3
y1=-7+(3*2)=-1
得到最优解为x=1,y=2

参考代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
int lgcd(int a, int b, int &x, int &y) {
    if (!b) {
        x = 1;
        y = 0;
        return a;
    }
    int d = lgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
__int128 flr(__int128 a, __int128 b) {
    if (a >= 0) return a / b;
    return -((-a + b - 1) / b);
}
__int128 cl(__int128 a, __int128 b) {
    if (a >= 0) return (a + b - 1) / b;
    return -((-a) / b);
}
ostream& operator<<(ostream& os, __int128 n) {
    if (n == 0) return os << '0';
    if (n < 0) {
        os << '-';
        n = -n;
    }
    string s;
    while (n) {
        s += char('0' + n % 10);
        n /= 10;
    }
    reverse(s.begin(), s.end());
    return os << s;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;
    while (T--) {
        int L, a, b;
        cin >> L >> a >> b;
        int x, y;
        int g = lgcd(a, b, x, y);

        if (L % g != 0) {
            cout << "No" << endl;
            continue;
        }
        __int128 X = (__int128)x * (L / g);
        __int128 Y = (__int128)y * (L / g);

        if (X < 0 && Y < 0) {
            cout << "No" << endl;
            continue;
        }
        __int128 s1 = b / g;
        __int128 s2 = a / g;
        __int128 t_min = cl(-X, s1);
        __int128 t_max = flr(Y, s2);

        if (t_min > t_max) {
            cout << "No" << endl;
            continue;
        }
        __int128 t0 = flr(Y - X, s1 + s2);
        vector<__int128> cand = {t_min, t_max};
        for (__int128 d = -5; d <= 5; ++d) {
            cand.push_back(t0 + d);
        }
        sort(cand.begin(), cand.end());
        cand.erase(unique(cand.begin(), cand.end()), cand.end());
        bool ok = false;
        __int128 bestX = 0, bestY = 0, bestMax = (__int128)1 << 120;
        for (__int128 t : cand) {
            if (t < t_min || t > t_max) continue;
            __int128 c1 = X + s1 * t;
            __int128 c2 = Y - s2 * t;
            if (c1 < 0 || c2 < 0) continue;
            __int128 cur = max(c1, c2);
            if (cur < bestMax) {
                bestMax = cur;
                bestX = c1;
                bestY = c2;
                ok = true;
            }
        }
        if (!ok) {
            cout << "No" << endl;
        } else {
            cout << "Yes" << endl;
            cout << bestX << ' ' << bestY << endl;
        }
    }
    return 0;
}