JOIG 2021/2022 F 题解
题意:给定一张 个点, 条边的无向图(保证没有重边、自环)。边有两种, 时,经过后手中的值 ; 时,经过后手中的值 下取整。给定 个询问以及常数 ,初始在点 上,每一次给定目标点 ,需要你求出最小的初始值,使得存在一种方案,使得到达 时该数 。若最小初始值 则输出 Large
。
做法: 次 Dijkstra 不可取,但是计算过程有一定启发性。
考虑将 变为 。那么可以将初值设为 ,对于 ,该值 ;对于 ,该值 。最后得出的一定是最小值。
像这样就只能做 次 Dijkstra,T 飞。
那么考虑反过来,从 开始走。怎么做呢?
考虑 对于答案的贡献。由于最后答案会变成 ,倒过来推就是每一个 会对其后继中 的边产生贡献。
那么就想到维护一个三元组进行 Dijkstra。转移的状态包括当前的答案、当前所在的点以及当前经过的 数量。
那么转移就很显然了。
当前如果为 ,那么当前的边权要乘上 ,其中 表示经过的 的边数。否则就需要更新 ,接着转移就行了。注意到这个时候有 的变化,所以需要分层图。由题面容易得到层数为 级别,复杂度便保证为 了。
细节在于最后答案为 ,所以初值为 ,每一次遇到 加上 ( 初始为 ),随后更新 ,这样就能保证这个 的贡献也能算上去。
代码如下。
#include <bits/stdc++.h>
using namespace std;
template <typename T> inline void read(T &x) {
x = 0; char ch = getchar();
while (!isdigit(ch)) ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
}
const int N = 2e5 + 10;
int n, m, q, l, cnt, bin[31], head[N], dis[N][31];
struct Node {
int val, cur, pw;
inline bool operator <(const Node &X) const {
return val > X.val;
}
};
priority_queue <Node> que;
struct Edge { int to, nxt, col; } e[N << 1];
inline void addEdge(int u, int v, int col) {
e[++cnt].to = v, e[cnt].nxt = head[u];
e[cnt].col = col, head[u] = cnt; return ;
}
inline void dijkstra() {
que.push((Node) {1, 1, 0});
memset(dis, 0x3f, sizeof(dis)); dis[1][0] = 1;
while (!que.empty()) {
Node awa = que.top(); que.pop();
int cur = awa.cur, pw = awa.pw;
for (int i = head[cur]; i; i = e[i].nxt) {
int to = e[i].to, col = e[i].col;
if (col == 1 && dis[to][pw] > dis[cur][pw] + bin[pw]) {
dis[to][pw] = dis[cur][pw] + bin[pw];
if (dis[to][pw] <= l) que.push((Node) {dis[to][pw], to, pw});
} else if (col == 2 && dis[to][pw + 1] > dis[cur][pw] + bin[pw]) {
dis[to][pw + 1] = dis[cur][pw] + bin[pw];
if (dis[to][pw + 1] <= l) que.push((Node) {dis[to][pw + 1], to, pw + 1});
}
}
}
return ;
}
int main() {
read(n), read(m), read(q), read(l);
for (int u, v, col; m--; ) {
read(u), read(v), read(col);
addEdge(u, v, col), addEdge(v, u, col);
}
bin[0] = 1; for (int i = 1; i < 31; ++i) bin[i] = bin[i - 1] << 1;
dijkstra();
while (q--) {
int p; read(p); int curans = 2e9;
for (int i = 0; i < 31; ++i) curans = min(curans, dis[p][i]);
if (curans > l) puts("Large");
else printf("%d\n", curans);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现