牛客练习赛60 - D
斩杀线计算大师
https://ac.nowcoder.com/acm/problem/204271
题意:
给定 a, b,c,k,求 x,y,z,使得:ax + by + cz = k,且 x >= 0,y >= 0,z >= 0
分析:
扩展欧几里得只能求二元一次方程,自然想到枚举 z 来求 x,y;看到 k 的范围有点大,如果 k = 2*p,c = 2,p 为一个大质数,肯定是跑不过的,考虑枚举 ax + by 的值,设 ax + by = k0,当 k0 = gcd(a,b)d 时 x,y 才会有解,那就有 gcd(a,b)d + cz = k,直接扩欧求出 d 即可,然后在用扩欧求解 ax + by = k0 即可,需要注意的是:cz >= 0,所以 gcd(a,b)d <= k,当 d 取最小非负整数解一定会满足这个条件,同样 x 取最小非负整数解时一定会满足 ax <= k0 吗?为了满足 ax <= k0,k0 就越大越好,也就是 d 越大越好;而扩欧求解后有通解:d' = d + tc/gcd(a,b,c),t 为整数,再结合 gcd(a,b)d <= k,就能得到 d 的最大取值了
代码:
#include <bits/stdc++.h>
#define x first
#define y second
#define pii pair<int,int>
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
using namespace std;
typedef long long LL;
const int maxn = 2e3+23;
LL ex_gcd(LL a,LL b,LL &x,LL &y){
if(b == 0){x = 1; y = 0; return a;}
LL gcd = ex_gcd(b,a%b,x,y);
LL t = x; x = y; y = t-a/b*y;
return gcd;
}
LL solve(LL a,LL b,LL &x,LL &y,LL k){ //求解 ax+by = k 的最小非负整数 x
LL gcd = ex_gcd(a,b,x,y);
x = k/gcd*x;
LL mod = b/gcd;
x = (x % mod + mod) % mod;
y = (k-a*x)/b;
return gcd;
}
int main(){
LL a,b,c,k,x,y,z;
cin >> a >> b >> c >> k;
LL g = __gcd(a,b);
LL gcd = solve(g,c,x,y,k);
LL d = x, mod = c/gcd;
LL t = (k-d*g)/(mod*g);
d += mod*t; //满足条件的最大的d
z = (k-d*g)/c;
LL k0 = d*g;
solve(a,b,x,y,k0);
cout << x << " " << y << " "<< z << '\n';
return 0;
}


查看11道真题和解析