鱼C论坛

 找回密码
 立即注册
查看: 2050|回复: 12

[心之碎片] - 20240810模拟赛

[复制链接]
回帖奖励 3 鱼币 回复本帖可获得 3 鱼币奖励! 每人限 1 次
发表于 2024-8-10 21:05:32 | 显示全部楼层 |阅读模式

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

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

x
总结与反思
A - 递归要贴合意义, 敢写
B - 树上问题应该多画画图找性质
D - 遇到必须经过小于 w 的边之类问题想到 kruskal 重构树, dsu 预处理每个点的答案


A - 括号翻转
给定给一个字符串,其中含有很多括号,括号里的内容会被翻转,输出这个字符串去掉括号的结果。

没啥好说的...

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

  3. const int N = 5e5 + 5;

  4. string s;
  5. int L[N], R[N], n;
  6. stack<int> stk;

  7. void dfs(int l, int r, int rev) {
  8.     if (l > r)
  9.         return;
  10.     if (rev) {
  11.         for (int i = r; i >= l; i--) {
  12.             if (s[i] != '(' && s[i] != ')')
  13.                 cout << s[i];
  14.             else
  15.                 dfs(L[i] + 1, i - 1, rev ^ 1), i = L[i];
  16.         }
  17.     } else {
  18.         for (int i = l; i <= r; i++) {
  19.             if (s[i] != '(' && s[i] != ')')
  20.                 cout << s[i];
  21.             else
  22.                 dfs(i + 1, R[i] - 1, rev ^ 1), i = R[i];
  23.         }
  24.     }
  25. }

  26. int main() {
  27.     ios::sync_with_stdio(0);
  28.     cin.tie(0);

  29.     freopen("bracket.in", "r", stdin);
  30.     freopen("bracket.out", "w", stdout);

  31.     cin >> s;
  32.     n = s.size();
  33.     s = '-' + s;

  34.     for (int i = 1; i <= n; i++) {
  35.         if (s[i] == '(')
  36.             stk.push(i);
  37.         if (s[i] == ')') {
  38.             int x = stk.top();
  39.             stk.pop();

  40.             R[x] = i, L[i] = x;
  41.         }
  42.     }

  43.     dfs(1, n, 0);

  44.     return 0;
  45. }
复制代码


B - 香蕉
在一个树上给出 a, b, c, d, 问 a, b 和 c, d 之间的路径是否有相交

考试时候无脑线段树, 其实有很简单的做法, 画画图找出性质

  1. for (int i = 1; i <= m; i++) {
  2.         int u, v, x, y;
  3.         cin >> u >> v >> x >> y;
  4.         int S = getlca(u, v), T = getlca(x, y);
  5.         if (dep[S] < dep[T]) {
  6.             swap(S, T), swap(u, x), swap(v, y);
  7.         }
  8.         if (getlca(S, x) == S || getlca(S, y) == S)
  9.             cout << "YES\n";
  10.         else
  11.             cout << "NO\n";
  12.     }
复制代码


C - 排列盒子
原题可以转化,构造一个排列,设定一个大小关系,使得逆序对的数量最小。

发现总颜色数很小, 考虑状压安排顺序
考试的时候没有搞出来预处理逆序对, tle 了, 可惜啊

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

  3. typedef long long ll;

  4. const int N = 1e5 + 5;
  5. const int M = 20;

  6. // cnt[i][j] 表示 i 优先于 j 产生的逆序对个数
  7. ll cnt[M][M], sum[M];
  8. int n, k;
  9. ll f[(1 << M)];

  10. ll Cost(int x, int st) {
  11.     ll res = 0;
  12.     for (int i = 0; i < k; i++) {
  13.         if ((st >> i) & 1)
  14.             continue;
  15.         // x 优先于 i
  16.         res += cnt[x][i];
  17.     }
  18.     return res;
  19. }

  20. int main() {
  21.     ios::sync_with_stdio(0);
  22.     cin.tie(0);

  23.     freopen("box.in", "r", stdin);
  24.     freopen("box.out", "w", stdout);

  25.     cin >> n >> k;
  26.     for (int i = 1; i <= n; i++) {
  27.         int x;
  28.         cin >> x;
  29.         x--;

  30.         for (int j = 0; j < k; j++) {
  31.             if (j == x)
  32.                 continue;
  33.             // 假设 x 优先于 j, 那 x 前面的 j 的个数就是贡献
  34.             cnt[x][j] += sum[j];
  35.         }
  36.         sum[x]++;
  37.     }

  38.     memset(f, 0x3f, sizeof(f));

  39.     f[0] = 0;

  40.     for (int st = 0; st < (1 << k); st++) {
  41.         for (int i = 0; i < k; i++) {
  42.             if ((st >> i) & 1)
  43.                 continue;

  44.             f[st | (1 << i)] = min(f[st | (1 << i)], f[st] + Cost(i, st | (1 << i)));
  45.         }
  46.     }

  47.     cout << f[(1 << k) - 1];

  48.     return 0;
  49. }
复制代码


乱搞做法, 直接取最小值安排顺序, 但是有可能成环


  1.     for (int i = 1; i <= n; i++) {
  2.         int x;
  3.         cin >> x;

  4.         for (int j = 1; j <= k; j++) {
  5.             if (x != j) {
  6.                 p[x][j] += sum[j];
  7.             }
  8.         }
  9.         sum[x]++;
  10.     }

  11.     for (int i = 1; i <= k; i++) {
  12.         for (int j = i + 1; j <= k; j++) {
  13.             ans += min(p[i][j], p[j][i]);
  14.         }
  15.     }
  16. }
复制代码


D - 花园
Mr. Panda 有 N 个花园,编号从 1 到 N 。对于编号为 i 的花园,花园里只有一朵花,颜色为  。花园与花园之间有道路连接(道路是双向的)。每条道路都有一个花费,表示经过该道路花费的时间。
Mr. Panda 喜欢在他的N个花园中转悠,然后采尽可能多的同种颜色的花
然而,有时候他并不想花太多时间走同一段路
现在问题来了,每一次 Mr. Panda 会告诉你:他从哪个花园开始出发和他能忍受的走同一段路的花费的最大值w(也就是说,只有费用不超过w的道路可以通行)
请你判断Mr. Panda最多能采到的花是哪种颜色的花。如果有多种颜色符合条件,选择颜色编号最小的输出

这种的关于路径最大值最小要想最小生成树, 进而想到 kruskal 重构树
那么 lca 就是边权最大值, 每次询问在 lca 的子树内就是活动范围
那么怎么知道答案? 时间太大, 只能看看能不能提前全出来, 那就用 dsu 吧

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

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

  6. // 和最大边权最小有关, 考虑 kruskal 重构树
  7. // 建出来之后对于 u, 她的活动范围就是最大的权值不超过 w 的点的子树
  8. // 然后就是询问区间众数, 这里用树上启发式合并来做, 求出每个点所在子树的答案, 也可以用线段树合并

  9. // Global
  10. int n, m, type, c[N];

  11. // Kruskal tree
  12. vector<int> e[M];
  13. int val[M];

  14. struct Kru {
  15.     int u, v, w;
  16. } edges[K];

  17. struct DSU {
  18.     int f[M], tot;

  19.     void Init() {
  20.         iota(f, f + M, 0);
  21.         tot = n;
  22.     }

  23.     int Find(int x) {
  24.         if (x == f[x])
  25.             return x;
  26.         return (f[x] = Find(f[x]));
  27.     }

  28.     int Merge(int x, int y) {
  29.         x = Find(x), y = Find(y);

  30.         if (x == y)
  31.             return 0;

  32.         tot++;
  33.         f[x] = tot, f[y] = tot;
  34.         e[tot].emplace_back(x);
  35.         e[tot].emplace_back(y);
  36.         return tot;
  37.     }
  38. } dsu;

  39. void Kruskal() {
  40.     dsu.Init();
  41.     val[0] = 1e9;

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

  43.     for (int i = 1; i <= m; i++) {
  44.         int cur = dsu.Merge(edges[i].u, edges[i].v);
  45.         if (cur)
  46.             val[cur] = edges[i].w;
  47.     }
  48. }

  49. // DSU on tree
  50. int cnt[M], tot, ans[M], mxid, mxap;
  51. int f[M][18], hc[M], dfn[M], rdfn[M], siz[M];

  52. void dfs0(int u, int pa) {
  53.     f[u][0] = pa;
  54.     siz[u] = 1;
  55.     dfn[u] = ++tot;
  56.     rdfn[tot] = u;

  57.     for (int i = 1; i < 18; i++) {
  58.         f[u][i] = f[f[u][i - 1]][i - 1];
  59.     }

  60.     for (auto ed : e[u]) {
  61.         if (ed == pa)
  62.             continue;
  63.         dfs0(ed, u);

  64.         siz[u] += siz[ed];
  65.         if (siz[hc[u]] < siz[ed])
  66.             hc[u] = ed;
  67.     }
  68. }

  69. void Modify(int col) {
  70.     cnt[col]++;
  71.     if (cnt[col] == mxap) {
  72.         mxid = min(mxid, col);
  73.     } else if (cnt[col] > mxap) {
  74.         mxap = cnt[col];
  75.         mxid = col;
  76.     }
  77. }

  78. void Add(int u) {
  79.     for (int i = dfn[u]; i < dfn[u] + siz[u]; i++) {
  80.         if (rdfn[i] > n)
  81.             continue;
  82.         Modify(c[rdfn[i]]);
  83.     }
  84. }

  85. void Del(int u) {
  86.     mxap = 0, mxid = 1e9;

  87.     for (int i = dfn[u]; i < dfn[u] + siz[u]; i++) {
  88.         if (rdfn[i] <= n)
  89.             cnt[c[rdfn[i]]] = 0;
  90.     }
  91. }

  92. void Solve(int u, int pa, bool keep) {
  93.     for (auto ed : e[u]) {
  94.         if (ed == pa || ed == hc[u])
  95.             continue;
  96.         Solve(ed, u, 0);
  97.     }

  98.     if (hc[u])
  99.         Solve(hc[u], u, 1);

  100.     for (auto ed : e[u]) {
  101.         if (ed == pa || ed == hc[u])
  102.             continue;

  103.         Add(ed);
  104.     }
  105.     if (u <= n)
  106.         Modify(c[u]);

  107.     ans[u] = mxid;

  108.     if (keep)
  109.         return;

  110.     Del(u);
  111. }

  112. int main() {
  113.     ios::sync_with_stdio(0);
  114.     cin.tie(0);

  115.     freopen("garden.in", "r", stdin);
  116.     freopen("garden.out", "w", stdout);

  117.     cin >> n >> m >> type;
  118.     for (int i = 1; i <= n; i++) {
  119.         cin >> c[i];
  120.     }
  121.     for (int i = 1; i <= m; i++) {
  122.         int u, v, w;
  123.         cin >> u >> v >> w;
  124.         edges[i] = { u, v, w };
  125.     }

  126.     Kruskal();
  127.     for (int i = dsu.tot; i; i--) {
  128.         if (!dfn[i]) {
  129.             dfs0(i, 0);
  130.             Solve(i, 0, 0);
  131.         }
  132.     }

  133.     int last = 0, q;

  134.     cin >> q;
  135.     while (q--) {
  136.         int x, w;
  137.         cin >> x >> w;

  138.         if (type) {
  139.             x ^= last;
  140.             w ^= last;
  141.         }

  142.         for (int i = 17; i >= 0; i--) {
  143.             if (val[f[x][i]] <= w)
  144.                 x = f[x][i];
  145.         }
  146.         last = ans[x];

  147.         cout << ans[x] << '\n';
  148.     }

  149.     return 0;
  150. }
复制代码

本帖被以下淘专辑推荐:

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

使用道具 举报

发表于 2024-8-10 21:15:52 | 显示全部楼层
看起来你在进行一些关于算法和数据结构的深入探讨,特别是在模拟赛中的总结与反思部分。让我试着用更幽默的方式来解释你提到的一些重要观点,尤其是关于括号翻转的问题。

### 括号翻转简单明了的小故事

想象一下,你有一个神奇的盒子,里面住着一群括号(当然它们都是有性格的)。这个盒子里有两种括号:左括号(`(`)和右括号(`)`),它们总是成对出现,就像一对恋人。当然,这些括号决定了他们的命运——如果它们不在一起,就会产生混乱,比如变成“()”就好像分开散步的情侣。

#### 算法大冒险:DFS与括号翻转

你决定要把这些括号里的内容翻转过来,让它们体验一下“逆风翻盘”的感觉。你使用深度优先搜索(DFS)这一神奇的工具,带着勇气深入这个盒子。以下是你旅程中的几个关键步骤:

1. **递归函数(dfs)**:就像你在幽暗的森林中探险,每深入一步就要考虑周围的环境。如果你到了一个括号的开头,就打个叉,然后反向跟随它的伙伴,直到找到结尾。在这个过程中,你就能把里面的内容翻转过来了。

2. **翻转的时机**:当你看到左括号时,就要准备好翻转;而当你遇到右括号时,你要立刻把想要翻转的内容倒过来,正如在聚会上突然转身跳舞那样令人惊讶!

3. **输出结果**:最后,当你翻转完所有内容,所有的括号都重新组合的时候,你会感到无比自豪,就像看到所有情侣成功重聚的那一瞬间!你可以愉快地打印出最终结果,呼喊出“成功翻转,我是最棒的!”

### 结尾小贴士

每次在处理这种括号问题时,多画图、多理解其中的逻辑,总会让你的代码像魔术般流畅。而且,别忘了在适当的时候,给自己来一段轻松的笑话,这样即使面对复杂的问题,也能保持心情愉快,就像“为什么括号不喜欢上课?因为它们不想被分开!”

希望这段小故事能让你在算法的海洋中游得更顺畅!如果你有其他问题或想法,随时欢迎交流哦!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-8-14 18:03:45 | 显示全部楼层
FishC 发表于 2024-8-10 21:15
看起来你在进行一些关于算法和数据结构的深入探讨,特别是在模拟赛中的总结与反思部分。让我试着用更幽默的 ...

再来 5 个笑话, 每个大约 60 字
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-14 18:23:38 | 显示全部楼层
柿子饼同学 发表于 2024-08-14 18:03
再来 5 个笑话, 每个大约 60 字


当然可以!以下是五个轻松幽默的笑话,希望能让你会心一笑:

1. 有一天,一个程序员去海边度假。他看到海浪在拍打沙滩,忍不住感叹:“这也太简单了吧,只需要输入‘波’和‘涛’,就能生成这么美的画面!”旁边的渔民听了,默默记下了新钓鱼技巧。

2. 一只鸡去上计算机课,老师问:“你为什么要学编程?”鸡回答:“我想要跳出这道‘程序’的框框,体验一下‘自由’的‘外面’!”全班顿时面面相觑,鸡却已飞走了。

3. 两个二进制数在酒吧喝酒,其中一个醉了,满脸困惑地说:“我感觉自己好像变成了十进制!”另一个二进制一脸不屑:“别傻了,你其实只是加了一点‘余数’而已!”

4. 一位工程师对同事说:“我正在研究如何让猫与狗共处一室。”同事好奇问:“如何实现?”工程师回答:“其实很简单,只需把它们的命令反转就好。你叫猫,它就跑;你叫狗,它就静。”

5. 有一天,一颗萝卜被问:“你为何总是待在土里,不出来晒太阳?”萝卜无奈地答:“我也是想尝试阳光下的生活,不过我的‘土豆朋友’提醒我:‘小心,不要被切片了!’”

希望这些笑话让你的心情更加愉快!如果还想要更多轻松的话题,尽管告诉我!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-8-14 20:07:52 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

发表于 2024-8-16 08:30:06 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

发表于 2024-8-18 09:59:27 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

发表于 2024-8-18 11:31:35 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

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

回帖奖励 +3 鱼币

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

使用道具 举报

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

回帖奖励 +3 鱼币

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

使用道具 举报

发表于 2024-8-23 16:43:10 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

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

回帖奖励 +3 鱼币

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

使用道具 举报

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

回帖奖励 +3 鱼币

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-4-27 16:49

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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