题目大意为找出一组非负特解 x x x 和 y y y 使得 x w + y d = p xw + yd = p xw+yd=p 且 x + y < = n x + y <= n x+y<=n。
我们令 g = p % w g = p \% w g=p%w, x + a = p w x + a = \frac{p}{w} x+a=wp。于是我们将 x w + y d = p xw + yd = p xw+yd=p 转化为 x w + a w + g = p xw + aw + g = p xw+aw+g=p。换言之,就是 a w + g = y d aw + g = yd aw+g=yd。
a w + g = y d aw + g = yd aw+g=yd 也就是 a w ≡ − g % d ( m o d = d ) aw \equiv -g\%d (mod = d) aw≡−g%d(mod=d) 转换为同余方程问题。
a w + y d = − g % d aw + yd = -g\%d aw+yd=−g%d ,将扩展欧几里得返回的 x x x 乘上 − g % d -g\%d −g%d ,然后对 d d d 取模取最小非负值即可。
算法思路:
我们要保证 x + y < = n x + y <= n x+y<=n ,所以我们贪心的拿 w w w 和 d d d 中大的那个,这样得到的 x + y x + y x+y 就是最小的。这里我们先默认 w w w 大,我们贪心的拿 w w w 之后,发现有余数 g g g。于是我们要将多拿了的 w w w 和剩下的g,转换为若干数量的 d d d。
然后我们构造同余方程,将求得结果乘上 − g % d -g\%d −g%d,为了尽可能多拿 w w w,最后取最小非负整数。然后得到 w w w 和 d d d 的数量,若贪心的选还不能满足 x x x 和 y y y 非负,则判断为无解。
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef long long LL;
LL gcd(LL x, LL y){
return y == 0 ? x : gcd(y, x%y);
}
void exgcd(LL a, LL b, LL &x, LL &y){
if(!b) x = 1, y = 0;
else{
exgcd(b, a%b, y, x);
y -= (a / b) * x;
}
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
LL n, p, w, d, x, y, a = 0, b, g;
cin >> n >> p >> w >> d;
bool flag = false;
if(w < d){
swap(w, d);
flag = true;
}
g = p % w;
x = p / w;
exgcd(w, d, a, b);
a *= -(g % d)/gcd(w, d);
a = (a % d + d) % d;
x -= a;
y = (a*w + g) / d;
if(x*w + y*d == p && x + y <= n && x >= 0 && y >= 0){
if(flag) swap(x, y);
cout << x << " " << y << " " << n - x - y << endl;
}
else
cout << -1 << endl;
return 0;}