牛客练习赛60 D.斩杀线计算大师 同余最短路

原题链接: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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值