P9751 [CSP-J 2023] 旅游巴士

因为写了 bool bfs 但是没返回值喜提 RE $100\to 0$,痛失 AK,火大。


先考虑起终点都是 $k$ 倍数的限制,由于不能在边上停留,所以相当于问你从 $1\to n$ 有没有 $k$ 的倍数长度的路径。看起来很困难,但是注意到 $nk$ 似乎是一个很可行的数字,暴力建 $k$ 个图表示每个点走到的时候模 $k$ 的距离,所以一条边是由每张图的 $u$ 连向下个图的 $v$。判断能不能到,就是第一张图也就是模 $k$ 为 $0$ 的图中 $1\sim n$ 的可达性。在这张图中,任意一条路径都是满足长度为 $k$ 倍数的,所以我们省去了一个条件。

接下来考虑每条边开放时间,正着做好像非常不好做。枚举到达终点的时间,然后建反图,倒着逆推回去,判断每个点最晚什么时候到,看看能不能在非负整数时间内到达结点 $1$。显然答案具有单调性,那么套上一个二分即可。并且这边倒着逆推的过程中,因为边权都是 $1$,所以直接 bfs 复杂度即为 $k(n+m)$。

总复杂度 $\Theta(k(n+m)(\log (n+m)+\log k))$。

考场机子要跑 $1.16s$/ruo

/*
big sample 1.16s /ll

TernaryTree is so vegetable.

i love ccf please give me full pts 
*/

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1e4 + 2;
const int maxm = 2e4 + 2;
const int maxk = 1e2 + 2;
const int inf = 1e7;

struct edge {
    int to, next, w;
};

int n, m, k;
int head[maxn * maxk];
edge e[maxm * maxk];
int cnt;

void add_edge(int u, int v, int w) {
    e[++cnt].to = v;
    e[cnt].next = head[u];
    e[cnt].w = w;
    head[u] = cnt;
}

int q[maxn * maxk];
int hd, tl;
//queue<int> q;
int dis[maxn * maxk];

void bfs(int d) {
    memset(dis, -0x3f, sizeof(dis));
    hd = tl = 1;
    q[1] = n;
    dis[n] = d;
    while (hd <= tl) {
        int v = q[hd++];
        for (int i = head[v]; i; i = e[i].next) {
            int u = e[i].to;
            if (dis[v] > e[i].w && dis[u] == dis[0]) {
                dis[u] = dis[v] - 1;
                q[++tl] = u;
            }
        }
    }
}

signed main() {
    //freopen("bus.in", "r", stdin);
    //freopen("bus.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n >> m >> k;
    for (int i = 1, u, v, w; i <= m; i++) {
        cin >> u >> v >> w;
        for (int j = 0; j < k - 1; j++) add_edge(v + (j + 1) * n, u + j * n, w);
        add_edge(v, u + (k - 1) * n, w);
    }
    bfs(inf);
    if (dis[1] < 0) {
        cout << -1 << endl;
        return 0;
    }
    int l = 0, r = inf;
    while (l < r) {
        int mid = l + r >> 1;
        bfs(mid);
        if (dis[1] >= 0) r = mid;
        else l = mid + 1;
    }
    bfs(l);
    cout << l + (dis[1] + k - 1) / k * k - dis[1] << endl;
    return 0;
}
posted @   TernaKagiri  阅读(45)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示