日常刷题2025-3-6
1.日常刷题2025-3-162.日常训练2025-1-23.日常训练2025-1-34.日常训练2025-1-55.日常训练2025-1-86.日常训练2025-1-117.日常训练2025-1-128.日常训练2025-1-139.日常训练2025-1-1410.日常训练2025-1-1511.日常训练2025-1-1612.日常训练2025-1-1713.日常训练2025-1-1814.日常训练2025-1-1915.日常训练2025-1-2116.日常训练2025-1-2217.日常刷题2025-1-2318.日常训练2025-1-2419.日常刷题2025-1-2520.日常刷题21.日常刷题2025-2-622.日常刷题2025-2-923.日常刷题2025-2-1424.日常刷题2025-2-1525.日常刷题2025-2-1726.日常刷题2025-2-2027.日常刷题2025-2-2128.日常刷题2025-2-2229.日常刷题2025-2-2430.日常刷题2025-2-2631.日常刷题2025-2-2732.日常刷题2025-2-2833.日常刷题2025-3-134.日常刷题2025-3-235.日常刷题2025-3-336.日常刷题2025-3-5
37.日常刷题2025-3-6
38.日常刷题2025-3-739.日常刷题2025-3-840.日常刷题2025-3-941.日常刷题2025-3-1042.日常刷题2023-3-1143.日常刷题2025-3-1344.非常棒的二分和DP日常刷题2025-3-6
P10206 [JOI 2024 Final] 建设工程 2 / Construction Project 2
绿色
思路:最短路+二分
- 第一种情况,S 到 T 的最短路长度已经 ≤K,那么任何一种合法的加边方式都成立。直接输出 N×(N−1) / 2。
- 第二种情况,从 S 到某一点 X,X 再通过边权为 L 的边到达 Y ,Y 最后到达 T。
那么只需先预处理 S 到每个点的最短路,和 T 到每个点的最短路,在判断边权是否小于 K。
但这样枚举 X 和 Y 显然为超时,考虑到排序每个点到 T 的最短路,二分找出最后一个满足条件的数即可。
代码
#include <bits/stdc++.h> typedef std::pair<long long, long long> pll; typedef std::pair<int, int> pii; #define INF 0x3f3f3f3f #define MOD 998244353 using i64 = long long; const int N = 1e5+5; void solve(){ i64 n, m; std::cin >> n >> m; i64 s, t, l, k; std::cin >> s >> t >> l >> k; std::vector g(n+1, std::vector<pll>()); for (int i = 0; i < m; i++){ int u, v, w; std::cin >> u >> v >> w; g[u].push_back({v, w}); g[v].push_back({u, w}); } std::vector<i64> dis(n+1); std::vector<bool> vis(n+1); auto dij = [&](int st)->void{ for (int i = 1; i <= n; i++) dis[i] = LONG_LONG_MAX; for (int i = 1; i <= n; i++) vis[i] = 0; std::priority_queue<pll, std::vector<pll>, std::greater<pll> > q; q.push({0, st}); dis[st] = 0; while(!q.empty()){ auto [w, cur] = q.top(); q.pop(); if (vis[cur]) continue; vis[cur] = 1; for (auto [to, dd] : g[cur]){ if (dis[to] > dis[cur] + dd){ dis[to] = dis[cur] + dd; q.push({dis[to], to}); } } } }; dij(t); if(dis[s]<=k){ std::cout << n*(n-1)/2 << '\n'; return; } std::vector<i64> dis2(n+1); for (int i = 1; i <= n; i++) dis2[i] = dis[i]; std::sort(dis2.begin()+1, dis2.end()); dij(s); i64 ans = 0; for (int i = 1; i <= n; i++){ if (dis[i] == LONG_LONG_MAX) continue; i64 lo = 0, r = n; while (lo < r){ i64 mid = (lo + r + 1)/2; if (dis2[mid] <= k - dis[i] - l){ lo = mid; }else{ r = mid - 1; } } ans += lo; } std::cout << ans << '\n'; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2); int t = 1, i; for (i = 0; i < t; i++){ solve(); } return 0; }
本文作者:califeee
本文链接:https://www.cnblogs.com/califeee/p/18754255
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步