原题链接:https://ac.nowcoder.com/acm/contest/4853/D
题意
a
x
+
b
y
+
c
z
=
k
ax+by+cz=k
ax+by+cz=k
求
x
,
y
,
z
的
合
法
取
值
,
并
输
出
一
组
解
求x,y,z的合法取值,并输出一组解
求x,y,z的合法取值,并输出一组解
分析
这题有个简单的做法,就是枚举一个数,然后用拓展欧几里得,这里介绍另一种做法
首先对式子进行变形,我们设 k = t c + p k=tc+p k=tc+p,这样p就是k%c的值,所以值域就在[0,c)之间,之后我们只要再构造一组解满足 a x + b y = p ax+by=p ax+by=p就可以满足题意了,这里就可以用到同余最短路求出满足膜c状态下p的最小值,同时记录一下路径就可以了。
如果对同余最短路不熟悉的,先学习一下这篇博客传送门
Code
#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define re register
typedef long long ll;
typedef pair<ll, ll> PII;
const int N = 1e6 + 10, M = 1e6 + 5, INF = 0x3f3f3f3f;
const int MOD = 998244353;
struct Edge {
int to, next, w;
}e[M];
int cnt, h[N], vis[N], n, m, ed;
ll dis[N], res[3], a, b, c, k;
void add(int u, int v, int w) {
e[cnt].to = v;
e[cnt].w = w;
e[cnt].next = h[u];
h[u] = cnt++;
}
PII edge[M];
void spfa() {
memset(dis, 0x3f, sizeof dis);
queue<int> q;
q.push(0); vis[0] = 1; dis[0] = 0;
while (q.size()) {
int u = q.front();
q.pop(); vis[u] = 0;
for (int i = h[u]; ~i; i = e[i].next) {
int v = e[i].to;
if (dis[v] > dis[u] + e[i].w) {
dis[v] = dis[u] + e[i].w;
edge[v] = {u, e[i].w == b ? 1 : 0};
if (!vis[v]) {
q.push(v);
vis[v] = 1;
}
}
}
}
}
void solve() {
cin >> a >> b >> c >> k;
memset(h, -1, sizeof h);
ed = k % c;
for (int i = 0; i < c; i++) {
add(i, (i + a) % c, a);
add(i, (i + b) % c, b);
}
spfa();
int now = ed;
while (now != 0) {
res[edge[now].se]++;
now = edge[now].fi;
}
res[2] = (k - res[0] * a - res[1] * b) / c;
cout << res[0] << " " << res[1] << " " << res[2] << endl;
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
#ifdef ACM_LOCAL
freopen("input", "r", stdin);
freopen("output", "w", stdout);
#endif
solve();
}