鱼C论坛

 找回密码
 立即注册
查看: 2337|回复: 11

[心之碎片] - 20240809模拟赛

[复制链接]
发表于 2024-8-9 21:45:19 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
总结与反思
F  - 最小生成树相关优先考虑按照边权分类
G - 不好枚举, 可以考虑构造搜索答案, 要注意阶段的区分, 数字太大考虑同余
H - 求很多点之间的最短路我们可以建立超级源点向每个关键点连边, 图论相关一定要注意图是否连通, 构建新图考虑一个点到另外一个点的花费等等


F - MST Unification
简单题, 考试时候用 kruskal 重构树水过去了, 后来才发现大家边求 mst 边求答案...
考虑什么时候会发生 mst 不唯一的情况, 当然也就是两个边权值一样, 但是一个边加了另一个边加不了的时候, 所以没了

  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. const int N = 2e5 + 5;

  4. struct DSU{
  5.     int f[N];

  6.     DSU(){ iota(f, f + N, 0); }

  7.     int Find(int x){
  8.         if(f[x] == x) return x;
  9.         return (f[x] = Find(f[x]));
  10.     }

  11.     bool Iseq(int x, int y){
  12.         x = Find(x), y = Find(y);
  13.         return (x == y);
  14.     }

  15.     void Merge(int x, int y){
  16.         f[Find(x)] = Find(y);
  17.     }
  18. } dsu;

  19. struct Edge{
  20.     int u, v, w;
  21. } e[N];

  22. int n, m, ans;
  23. int stk[N], top;

  24. int main(){
  25.     ios::sync_with_stdio(0);
  26.     cin.tie(0);
  27.    
  28.     cin >> n >> m;
  29.     for(int i = 1; i <= m; i++){
  30.         int u, v, w;
  31.         cin >> u >> v >> w;
  32.         e[i] = {u, v, w};
  33.     }

  34.     sort(e + 1, e + m + 1, [](Edge& a, Edge& b){ return a.w < b.w; });

  35.     for(int i = 1; i <= m; i++){
  36.         int l = i, r = i;
  37.         while(r <= m && e[r].w == e[l].w) r++;
  38.         r--;

  39.         top = 0;
  40.         for(int j = l; j <= r; j++){
  41.             if(dsu.Iseq(e[j].u, e[j].v)) continue;
  42.             stk[++top] = j;
  43.         }

  44.         // 相同边权, 本来有可能被加进去的, 现在加不进去所以必须让她边权 +1
  45.         for(int j = 1; j <= top; j++){
  46.             if(dsu.Iseq(e[stk[j]].u, e[stk[j]].v)){
  47.                 ans++;
  48.                 continue;
  49.             }
  50.             
  51.             dsu.Merge(e[stk[j]].u, e[stk[j]].v);
  52.         }

  53.         i = r;
  54.     }

  55.     cout << ans;
  56.    
  57.     return 0;
  58. }
复制代码


G - [ABC077D] Small Multiple
没想出来, 后来发现很简单
枚举 d 会超时, 就想着构造答案
每次 K*d 这个数可以 *10 或者 +1, 后者会对数位和产生贡献, 然后广搜, 要求是 k 的倍数, 所以数字 %k, 最后 %k == 0 的状态就是最优解

解释一下为什么不用考虑进位:进位的情况一定对应一种其他的情况,我们发现另一种情况各位和更小,所以这种情况一定是不优的,所以存在f里的不存在进位的影响。

  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. // K*d 不好枚举 d, 考虑构造答案
  4. // 这时不仅要想到 dp 还要想到搜索(记忆化)
  5. // 构造数字有 +1 *10 两个操作, 只需要判断 %K == 0 即可
  6. // 代价分别是 1, 0, 用 deque 跑 0/1bfs 就行了
  7. // 构造的阶段就是一位一位的枚举

  8. const int N = 1e5 + 5;

  9. struct St{
  10.     // %k 的余数, 现在的数位和
  11.     int num, sum;
  12. };

  13. int f[N];
  14. deque<St> q;
  15. int k;

  16. int main(){
  17.     ios::sync_with_stdio(0);
  18.     cin.tie(0);
  19.    
  20.     cin >> k;
  21.     memset(f, 0x3f, sizeof(f));
  22.     q.push_back({1, 1});
  23.     f[1] = 1;

  24.     int temp;
  25.     while(!q.empty()){
  26.         auto cur = q.front();
  27.         q.pop_front();

  28.         if(cur.num == 0){
  29.             cout << cur.sum;
  30.             return 0;
  31.         }
  32.         
  33.         temp = cur.num*10 % k;
  34.         if(cur.sum < f[temp]){
  35.             f[temp] = cur.sum;
  36.             q.push_front({temp, cur.sum});
  37.         }
  38.         
  39.         temp = (cur.num + 1) % k;
  40.         if(cur.sum + 1 < f[temp]){
  41.             f[temp] = cur.sum + 1;
  42.             q.push_back({temp, cur.sum + 1});
  43.         }
  44.     }
  45.    
  46.     return 0;
  47. }
复制代码


G - Cheap Robot
没啥好说的, 没考虑搞超级源点, 写暴力也没判断是否连通, 挂了
我用了 kruskal 重构树, 其实求个最小生成树倍增求边上最大值一样的, 考虑两个点之间怎么走就出来了

  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. typedef long long ll;

  4. const int N = 1e5 + 5;
  5. const int K = 2e5 + 5;
  6. const int M = 3e5 + 5;

  7. struct Node {
  8.     int id;
  9.     ll w;

  10.     bool operator<(const Node& t) const { return w > t.w; }
  11. };

  12. struct Kru {
  13.     int u, v;
  14.     ll w;
  15. } edges[M << 1];
  16. int cnt;

  17. int n, m, k, q;
  18. vector<Node> g[N];
  19. vector<int> e[K];
  20. ll dist[N], val[K];
  21. bitset<N> vis;
  22. priority_queue<Node> p;
  23. int f[K][19], dep[K];

  24. void Dijkstra() {
  25.     memset(dist, 0x3f, sizeof(dist));
  26.     p.push({ 0, 0 });
  27.     dist[0] = 0;

  28.     while (!p.empty()) {
  29.         auto u = p.top().id;
  30.         p.pop();

  31.         if (vis[u])
  32.             continue;
  33.         vis[u] = 1;

  34.         for (auto ed : g[u]) {
  35.             int v = ed.id;
  36.             ll w = ed.w;
  37.             if (dist[u] + w < dist[v]) {
  38.                 dist[v] = dist[u] + w;
  39.                 if (!vis[v])
  40.                     p.push({ v, dist[v] });
  41.             }
  42.         }
  43.     }
  44. }

  45. struct DSU {
  46.     int f[K], tot;

  47.     void Init() {
  48.         iota(f, f + K, 0);
  49.         tot = n;
  50.     }

  51.     int Find(int x) {
  52.         if (x == f[x])
  53.             return x;
  54.         return (f[x] = Find(f[x]));
  55.     }

  56.     int Merge(int x, int y) {
  57.         x = Find(x), y = Find(y);
  58.         if (x == y)
  59.             return 0;

  60.         tot++;
  61.         f[x] = tot;
  62.         f[y] = tot;

  63.         e[tot].emplace_back(x);
  64.         e[tot].emplace_back(y);
  65.         e[x].emplace_back(tot);
  66.         e[y].emplace_back(tot);
  67.         return tot;
  68.     }
  69. } dsu;

  70. void Kruskal() {
  71.     dsu.Init();

  72.     for (int i = 1; i <= n; i++) {
  73.         for (auto j : g[i]) {
  74.             if (j.id > 0) {
  75.                 edges[++cnt] = { i, j.id, dist[i] + dist[j.id] + j.w };
  76.             }
  77.         }
  78.     }

  79.     sort(edges + 1, edges + cnt + 1, [](Kru& a, Kru& b) { return a.w < b.w; });

  80.     int u, v, w, cur;
  81.     for (int i = 1; i <= cnt; i++) {
  82.         u = edges[i].u;
  83.         v = edges[i].v;
  84.         w = edges[i].w;
  85.         cur = dsu.Merge(u, v);

  86.         if (cur)
  87.             val[cur] = w;
  88.     }
  89. }

  90. void dfs(int u, int pa) {
  91.     f[u][0] = pa;
  92.     dep[u] = dep[pa] + 1;

  93.     for (int i = 1; i < 19; i++) {
  94.         f[u][i] = f[f[u][i - 1]][i - 1];
  95.     }

  96.     for (auto ed : e[u]) {
  97.         if (ed == pa)
  98.             continue;
  99.         dfs(ed, u);
  100.     }
  101. }

  102. int lca(int x, int y) {
  103.     if (dep[x] < dep[y])
  104.         swap(x, y);

  105.     int d = dep[x] - dep[y];
  106.     for (int i = 18; i >= 0; i--) {
  107.         if ((d >> i) & 1) {
  108.             x = f[x][i];
  109.         }
  110.     }

  111.     if (x == y)
  112.         return x;

  113.     for (int i = 18; i >= 0; i--) {
  114.         if (f[x][i] != f[y][i]) {
  115.             x = f[x][i];
  116.             y = f[y][i];
  117.         }
  118.     }

  119.     return f[x][0];
  120. }

  121. int main() {
  122.     ios::sync_with_stdio(0);
  123.     cin.tie(0);

  124.     cin >> n >> m >> k >> q;
  125.     for (int i = 1; i <= m; i++) {
  126.         int u, v, w;
  127.         cin >> u >> v >> w;
  128.         g[u].push_back({ v, w });
  129.         g[v].push_back({ u, w });
  130.     }
  131.     for (int i = 1; i <= k; i++) {
  132.         g[0].push_back({ i, 0 });
  133.         g[i].push_back({ 0, 0 });
  134.     }

  135.     Dijkstra();
  136.     Kruskal();
  137.     dfs(dsu.tot, 0);

  138.     while (q--) {
  139.         int x, y;
  140.         cin >> x >> y;
  141.         cout << val[lca(x, y)] << '\n';
  142.     }

  143.     return 0;
  144. }
复制代码

本帖被以下淘专辑推荐:

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-8-9 22:33:01 | 显示全部楼层

回帖奖励 +3 鱼币

大佬收下我的膝盖
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-9 23:22:04 | 显示全部楼层

回帖奖励 +3 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-10 09:44:30 | 显示全部楼层

回帖奖励 +3 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-8-11 19:13:10 | 显示全部楼层

回帖奖励 +3 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-8-18 10:00:04 | 显示全部楼层

回帖奖励 +3 鱼币

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-8-18 11:30:56 | 显示全部楼层
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-8-20 09:57:57 | 显示全部楼层

回帖奖励 +3 鱼币

学习学习
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-24 11:49:05 | 显示全部楼层

回帖奖励 +3 鱼币

&#128076;
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-29 09:23:15 | 显示全部楼层

回帖奖励 +3 鱼币

膜拜大佬/orz/orz
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-9-1 10:02:53 | 显示全部楼层

回帖奖励 +3 鱼币

唉,高山啊高山
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-9-4 17:16:21 | 显示全部楼层

回帖奖励 +3 鱼币

谢谢
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-27 17:03

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表