题意: 求的最小非负整数解
知识点: 裴蜀定理,扩展欧几里得算法
思路: 我们先简化符号为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;
}

京公网安备 11010502036488号