同余最短路
当出现形如“给定
同余最短路利用同余来构造一些状态,可以达到优化空间复杂度的目的。
类比 差分约束 方法,利用同余构造的这些状态可以看作单源最短路中的点。同余最短路的状态转移通常是这样的
例题¶
例题一¶
P3403 跳楼机
题目大意:给定
不妨假设
令
可以得到两个状态:
-
i \xrightarrow{y} (i+y) \bmod x -
i \xrightarrow{z} (i+z) \bmod x
注意通常选取一组
那么实际上相当于执行了最短路中的建边操作:
add(i, (i+y) % x, y)
add(i, (i+z) % x, z)
接下来只需要求出
加一是由于当前所在楼层也算一次。
参考实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100010;
const int INF = 0x3f3f3f3f;
ll h, x, y, z;
ll head[maxn << 1], tot;
ll dis[maxn], vis[maxn];
queue<int> q;
struct edge {
ll to, next, w;
} e[maxn << 1];
void add(ll u, ll v, ll w) {
e[++tot] = edge{v, head[u], w};
head[u] = tot;
}
void spfa() { // spfa算法,可看最短路部分
dis[1] = 1;
vis[1] = 1;
q.push(1);
while (!q.empty()) {
int u = q.front();
q.pop();
vis[u] = 0;
for (int i = head[u]; i; i = e[i].next) {
int v = e[i].to, w = e[i].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!vis[v]) {
q.push(v);
vis[v] = 1;
}
}
}
}
}
int main() {
memset(dis, INF, sizeof(dis));
scanf("%lld", &h);
scanf("%lld %lld %lld", &x, &y, &z);
if (x == 1 || y == 1 || z == 1) {
printf("%d\n", h);
return 0;
}
for (int i = 0; i < x; i++) {
add(i, (i + z) % x, z);
add(i, (i + y) % x, y);
}
spfa();
ll ans = 0;
for (int i = 0; i < x; i++) {
if (h >= dis[i]) ans += (h - dis[i]) / x + 1;
}
printf("%lld\n", ans);
return 0;
}
|
例题二¶
ARC084B Small Multiple
题目大意:给定
本题可以使用循环卷积优化完全背包在
观察到任意一个正整数都可以从
对于所有
每个
时间复杂度
习题¶
build本页面最近更新:,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:OI-wiki
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用