算法学习笔记(13):同余最短路
1.算法学习笔记(1):CDQ分治2.算法学习笔记(2):分块3.算法学习笔记(3):莫队算法4.算法学习笔记(4):FHQ平衡树(无旋平衡树)5.算法学习笔记(5):AC自动机6.算法学习笔记(6):优秀trick和性质合集7.算法学习笔记(7):数论8.算法学习笔记(9):第k大问题合集9.算法学习笔记(10):各种序的美好性质10.算法学习笔记(11):历史版本和线段树11.算法学习笔记(12):左偏树
12.算法学习笔记(13):同余最短路
13.算法学习笔记(14):区间最值操作和历史最值问题14.算法学习笔记(15): Splay树15.算法学习笔记(16):Link Cut Tree16.算法学习笔记(17):Slope trick17.算法学习笔记(18):珂朵莉树18.算法学习笔记(20):网络流19.算法学习笔记(21):数论分块20.算法学习笔记(22):莫比乌斯反演21.算法学习笔记(23):杜教筛22.算法学习笔记(24):筛法23.暑假集训学习笔记(1):lxl DS Day 124.暑假集训学习笔记(2):lxl DS Day 225.暑假集训学习笔记(3):lxl DS Day 326.多项式笔记27.生成函数笔记28.插头DP29.DP选讲做题记录 by 付乙淼30.拓展摩尔投票31.图论知识总结同余最短路
是一种通过同余把状态分类, 再通过建图跑最短路解决问题的算法。可以高效率解决一些特定的问题。 非常的奇妙。
算法
鉴于学不懂, 所以直接搬
P3403 跳楼机
有一栋高为
转化问题, 可以看成有多少个
都可以跳到, 可以跳到
如果这里懂了, 那么建边也就懂了。
边权为 。 边权为 。
最后从
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e5 + 10;
const ll INF = LONG_LONG_MAX;
int X, Y, Z, head[N], tot, vis[N];
ll H, d[N];
struct Edge{ int to, dis, nxt; }edge[N << 3];
void add(int x, int y, int z) { edge[++tot] = {y, z, head[x]}; head[x] = tot; }
#define fi first
#define se second
priority_queue< pair<ll, int> > q;
void dijk(int s) {
fill(d, d + X, INF);
d[s] = 1; q.push({-d[s], s});
while (!q.empty()) {
int u = q.top().se; q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = head[u]; i; i = edge[i].nxt) {
int v = edge[i].to;
if (!vis[v] && d[u] + edge[i].dis < d[v]) {
d[v] = d[u] + edge[i].dis;
q.push({-d[v], v});
}
}
}
}
int main() {
scanf("%lld%d%d%d", &H, &X, &Y, &Z);
if (X == 1 || Y == 1 || Z == 1) {
printf("%lld\n", H);
return 0;
}
for (int i = 0; i < X; i++) {
add(i, (i + Y) % X, Y);
add(i, (i + Z) % X, Z);
}
dijk(1);
ll ans = 0;
for (int i = 0; i < X; i++) if (H >= d[i]) ans += (H - d[i]) / X + 1;
printf("%lld", ans);
return 0;
}
[ABC077D] Small Multiple
输出
考虑很难办, 最质朴的做法就是枚举左右的倍数, 显然不行。 但是我们把所有数按数位和分类, 很难发现一个性质, 一个数一定可以由 若干
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int K, d[N], vis[N];
#define pf push_front
#define pb push_back
#define ls ((u * 10) % K)
#define rs ((u + 1) % K)
deque<int> q;
void bfs(int s) {
memset(d, 0x3f, sizeof d);
q.pb(s); d[s] = 1;
while (!q.empty()) {
int u = q.front(); q.pop_front();
if (u == 0) printf("%d", d[u]), exit(0);
vis[u] = 1;
if (!vis[ls] && d[ls] > d[u]) d[ls] = d[u], q.pf(ls);
if (!vis[rs] && d[rs] > d[u] + 1) d[rs] = d[u] + 1, q.pb(rs);
}
}
int main() {
scanf("%d", &K);
bfs(1);
return 0;
}
牛场围栏
考虑和跳楼机十分相似, 我们钦定一个最小的木棍为模数
墨墨的等式
考虑是牛场围栏和跳楼机的整合版, 答案统计的时候魔改一下就行了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App