题目描述
算术能力是每个炉石玩家必不可少的,假设现在有三种伤害卡,伤害值分别是a,b,ca,b,ca,b,c。并且每种伤害卡的数量你可以认为是无限的。现在牛牛想知道是否存在一种方式可以刚好造成kkk点伤害,输出x,y,zx,y,zx,y,z分别表示三种伤害卡的使用个数。
数据保证一定存在解。如果存在多组解,输出任意一组。
输入描述:
一行四个整数分别表示a, b, c, k.
输出描述:
一行输出三个整数分别表示x,y,z.
示例1
输入:3 4 5 20
输出:4 2 0
备注:
1≤a,b,c≤1e5
1e120≤k≤1e12
稍微说一下:通过遍历其中一个系数,然后用扩展欧几里得算法得到另外两个就行了,需要注意的是这题系数都要是正整数,所以需要变形一下,方法和过程都在代码里,所以
直接上代码,O(∩_∩)O哈哈~:
#include<cstdio>
using namespace std;
typedef long long LL;
LL exgcd(LL a, LL b, LL &x, LL &y){//扩展欧几里得算法
if (b == 0){
x = 1, y = 0;
return a;
}
LL ans = exgcd(b,a%b,x,y);
/******************************
x[i] = y[i+1]
y[i] = x[i+1] - K[i] * y[i+1]
******************************/
LL tmp = x;
x = y;
y = tmp - (a / b) * y;
return ans;
}
LL get(LL a, LL b, LL c) {//返回一组解
LL X, Y, gcd = exgcd(a, b, X, Y);
if (c % gcd) return -1;//c不是gcd的倍数->无解
if (b == 0) return c / gcd * X;//b为零的特殊情况
/******************************
设 x,y,K=c/gcd 其中x大于零 且 xa + yb = c;
所以 XK = (x + A), YK = (y - B);
Xa + Yb = gcd; ==> (x + A)a + (y - B)b = c;
Aa - Bb = 0; ==> A = kb, B = ka;
可得 x = XK - kb; ==> x = (XK % b + b) % b;
*******************************/
return (c / gcd * X % b + b) % b; //x为符合要求的最小正整数
}
int main(){
LL a, b, c, n;
scanf("%lld%lld%lld%lld", &a, &b, &c, &n);
for(LL i = 0; i * c <= n; ++i) {//对c进行遍历
LL k = n - i * c;
LL res = get(a, b, k);
if (res != -1) {
LL ans = b ? (k - a * res) / b : 0;
printf("%lld %lld %lld\n", res, ans, i);
break;
}
if (c == 0) {//c为零的特殊情况
break;
}
}
return 0;
}