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;
}
标签:pii,洛谷,P9751,int,题解,LL,vis,整数倍,dis
From: https://www.cnblogs.com/Milkcatqwq/p/17975417