洛谷 P9751 [CSP-J 2023] 旅游巴士 题解

Solution

  • 能在起点等 \(k\) 的非负整数倍相当于能在任意点等 \(k\) 的非负整数倍。
  • 由于离开的时间要是 \(k\) 的负整数倍,将每个点拆成 \(k\) 个点,\(dis_{i,j}\) 表示到了第 \(i\) 个点长度 \(\bmod\text{ }k\equiv j\) 的最短路径。
  • 转移时若时间未到,直接在原地等 \(k\) 的负整数倍时间直至可以通过。易证这样一定是最优的。注意到这样边权不全是 \(1\),跑 Dijkstra 即可。

时间复杂度 \(\mathcal{O}(mk\log(nk))\)

Code

考场代码,写得有些丑:

#include <bits/stdc++.h>
#define REP(i, l, r) for (int i = (l); i <= (r); ++ i)
#define DEP(i, r, l) for (int i = (r); i >= (l); -- i)
#define fi first
#define se second
using namespace std;
namespace Milkcat {
	typedef long long LL;
	typedef pair<int, int> pii;
	const int N = 1e6 + 5;
	LL n, m, k, u, v, w, dis[N];
	vector<pii> G[N];
	bool vis[N];
	int id(int u, int k) { return n * k + u; }
	LL updiv(LL a, LL b) { return (a + b - 1) / b; }
	int main() {
		cin >> n >> m >> k;
		REP(i, 1, m)
			cin >> u >> v >> w, G[u].push_back(pii(v, w));
		auto Dijkstra = [&]() {
			memset(dis, 0x3f, sizeof dis);
			priority_queue<pii, vector<pii>, greater<pii>> q;
			dis[1] = 0, q.push(pii(dis[1], 1));
			while (!q.empty()) {
				pii tmp = q.top(); q.pop();
				int u = tmp.se;
				if (vis[u]) continue;
				vis[u] = 1;
				for (pii qwq : G[(u - 1) % n + 1]) {
					int v = id(qwq.fi, (dis[u] + 1) % k), d = qwq.se;
					int w = max(updiv(d - dis[u], k), 0LL) * k + 1;
					if (dis[v] > dis[u] + w) {
						dis[v] = dis[u] + w;
						if (!vis[v]) q.push(pii(dis[v], v));
					}
				}
			}
		};
		Dijkstra();
		if (dis[n] > 1e9) cout << "-1\n";
		else cout << dis[n] << '\n';
		return 0;
	}
}
int main() {
//	freopen("bus.in", "r", stdin);
//	freopen("bus.out", "w", stdout);
	int T = 1;
	while (T --) Milkcat::main();
	return 0;
}
posted @ 2024-01-19 19:08  喵仔牛奶  阅读(88)  评论(0编辑  收藏  举报