鱼C论坛

 找回密码
 立即注册
查看: 1464|回复: 4

[心之碎片] - 20240807模拟赛

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

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

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

x
本帖最后由 柿子饼同学 于 2024-8-10 13:59 编辑
总结与反思
A - 只需要判断 可行性/可解性 要考虑前缀 min/max
B - 数学找规律先打表
C - 刷表法转化为填表法更好优化
D - 树剖是为了让我们 log 级别跳到顶, 并且维护一整条重链的信息, 轻孩子暴力存 (由一个一个跳祖先启发过来)



A - 牛宫
我们想知道 r 前面是否有小于她的, 这里只需要取前缀 min 就好
  1. #include <bits/stdc++.h>

  2. using namespace std;

  3. const int N = 400 + 5;
  4. const int inf = 114514;

  5. int n, m, a[N][N], s[N][N], res, st[N], t, b[N];

  6. inline int w(int u, int d, int i) { return s[d][i] - s[u - 1][i]; }

  7. signed main() {
  8.     ios::sync_with_stdio(0);
  9.     cin.tie(0);
  10.     cout.tie(0);

  11.     freopen("rec.in", "r", stdin);
  12.     freopen("rec.out", "w", stdout);

  13.     cin >> n >> m;
  14.     for (int i = 1; i <= n; i++) {
  15.         for (int j = 1; j <= m; j++) {
  16.             cin >> a[i][j];
  17.             s[i][j] = s[i][j - 1] + s[i - 1][j] - s[i - 1][j - 1] + a[i][j];
  18.         }
  19.     }
  20.     for (int p = 1; p <= n; p++) {
  21.         for (int q = p; q <= n; q++) {
  22.             for (int i = 1; i <= m; i++) b[i] = min(b[i - 1], w(p, q, i));
  23.             t = 0;
  24.             for (int i = 1; i <= m; i++)
  25.                 while (t < i && w(p, q, i) >= b[i - t - 1]) t++;
  26.             res = max(res, (q - p + 1) * t);
  27.         }
  28.     }

  29.     cout << res;

  30.     return 0;
  31. }
复制代码

B - GCD
选出两个正整数a,b,使得通过辗转相除求最大公约数时,递归调用次数最多。
斐波那契数列最大公约数定理(这谁知道啊...打表吧)
Gcd(F(m),F(n))=F(gcd(m,n))
然后就是高精度每次加一下即可

  1. #include <bits/stdc++.h>
  2. #define LL long long
  3. using namespace std;
  4. char str[20005];
  5. int m, b;
  6. LL num[2505], A[2505], B[2505], C[2505], P = 1e18;
  7. bool Cmp() {
  8.     if (b != m)
  9.         return b > m;
  10.     for (int i = b - 1; i >= 0; i--) {
  11.         if (C[i] != num[i])
  12.             return C[i] > num[i];
  13.     }
  14.     return false;
  15. }
  16. void Print(LL s[]) {
  17.     int k = b;
  18.     while (s[k] == 0) k--;
  19.     printf("%lld", s[k--]);
  20.     while (k >= 0) printf("%018lld", s[k--]);
  21. }
  22. LL getnum(int L, int R) {
  23.     LL res = 0;
  24.     for (int i = L; i <= R; i++) res = (res << 3) + (res << 1) + (str[i] ^ 48);
  25.     return res;
  26. }
  27. int main() {
  28.     freopen("gcd.in", "r", stdin);
  29.     freopen("gcd.out", "w", stdout);

  30.     scanf("%s", str);
  31.     int n = strlen(str);
  32.     int p = n % 18;
  33.     m = (n + 17) / 18;
  34.     int k = m - 1;
  35.     if (p != 0) {
  36.         num[k] = getnum(0, p - 1);
  37.         k--;
  38.     }
  39.     for (int i = p, j = 0; i < n; i += 18) {
  40.         num[k] = getnum(i, i + 17);
  41.         k--;
  42.     }
  43.     A[0] = 1, B[0] = 1, b = 1;
  44.     while (1) {
  45.         for (int i = 0; i < b; i++) {
  46.             C[i] += A[i] + B[i];
  47.             if (C[i] >= P) {
  48.                 C[i] -= P;
  49.                 C[i + 1]++;
  50.             }
  51.         }
  52.         if (C[b] > 0)
  53.             b++;
  54.         if (Cmp())
  55.             break;
  56.         for (int i = 0; i < b; i++) {
  57.             A[i] = B[i];
  58.             B[i] = C[i];
  59.             C[i] = 0;
  60.         }
  61.     }
  62.     Print(A);
  63.     putchar(' ');
  64.     Print(B);
  65.     return 0;
  66. }
复制代码

C - 排列逆序对
构造 1-n 的排列, 使得逆序对为 k, 求方案数
线段树优化超时了, 后来发现改成填表法之间用前缀和优化即可

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

  3. const int N = 5005;
  4. const int P = 1e9 + 7;

  5. int f[N], s[N];
  6. int n, m;

  7. // i(前 i 个数), j(现在要填的数), k(逆序对数)
  8. // f(i, k + i - j) += f(i - 1, k)
  9. // 刷表法不好优化, 转换一下
  10. // f(i, k) += f(i, k - i + j)
  11. // 即 f(i, k) = f(i, x), x 属于 [k - i + 1, k]
  12. // 于是乎前缀和优化

  13. int main() {
  14.     ios::sync_with_stdio(0);
  15.     cin.tie(0);

  16.     freopen("reverse.in", "r", stdin);
  17.     freopen("reverse.out", "w", stdout);

  18.     cin >> n >> m;
  19.     // 逆序对为 0 永远只有一种情况
  20.     s[0] = 1;

  21.     for (int i = 1; i <= n; i++) {
  22.         for (int k = 1; k <= m; k++) {
  23.             s[k] = (f[k] + s[k - 1]) % P;
  24.         }
  25.         for (int k = 0; k <= m; k++) {
  26.             if (k - i >= 0)
  27.                 f[k] = (s[k] - s[k - i] + P) % P;
  28.             else
  29.                 f[k] = s[k];
  30.         }
  31.     }

  32.     cout << f[m];

  33.     return 0;
  34. }
复制代码

D - [2010国家集训队]Crash的旅游计划

20% 的分数满足:n和指令的条数都不超过 1e3。
另 30% 的分数满足:n和指令的条数都不超过1e5 ,且输入的第 i 条道路,连接着 i 号地点和 i+1 号地点(详见样例2)。
另 20% 的分数满足:n和指令的条数都不超过1e5 ,除了 1 之外,每个点 i 与 (i + 1)/2 连边,即形成一棵完全二叉树。
另 10% 的分数满足:n和指令的条数都不超过1e5 ,且任何一个地点到 1 号地点需要通过的道路条数不超过 40。
100% 的分数满足:n和指令的条数都不超过1e5 。
80 分比较简单, 分别用暴力, 区间 max/min , 每个点向上跳, 同时维护这个点到除了这个子树的最长路径
100 分在向上跳的基础上, 直接维护整个重链的答案, 存上每个点出发去往一个轻孩子的最长路径, 向上就是 logn 的

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

  3. typedef pair<int, int> pii;

  4. const int N = 1e5 + 5;

  5. // Global
  6. vector<int> e[N];
  7. int val[N], n;

  8. // QTREE
  9. int dfn[N], siz[N], hc[N];
  10. int L[N], R[N], f[N], rdfn[N], tot;
  11. // L, R -> u 所在的重链的两端点编号, L 即 top

  12. void dfs0(int u, int pa) {
  13.     f[u] = pa;
  14.     siz[u] = 1;

  15.     for (auto v : e[u]) {
  16.         if (v == pa)
  17.             continue;
  18.         dfs0(v, u);

  19.         siz[u] += siz[v];
  20.         if (siz[hc[u]] < siz[v])
  21.             hc[u] = v;
  22.     }
  23. }

  24. void dfs1(int u, int t) {
  25.     L[u] = t;
  26.     dfn[u] = ++tot;
  27.     rdfn[tot] = u;

  28.     if (hc[u])
  29.         dfs1(hc[u], t), R[u] = R[hc[u]];
  30.     else
  31.         R[u] = u;

  32.     for (auto v : e[u]) {
  33.         if (v == f[u] || v == hc[u])
  34.             continue;
  35.         dfs1(v, v);
  36.     }
  37. }

  38. // s[u] 存和 u 相连的属于轻链的点, 第一个存该点所能拓展的最长路径, 第二个是她的编号
  39. multiset<pii, greater<pii> > s[N];
  40. // 如果这个点是重链的 top, rt[u] 就是对应线段树根
  41. int rt[N];

  42. struct Node {
  43.     int sum, lmax, rmax;

  44.     Node(){};
  45.     // sum 这个链的路径和
  46.     // lmax 这个链从上往下走, 再从轻孩子中下去的最长路径
  47.     // rmax 这个链从下往上走的最长路径
  48.     Node(int a, int b, int c) { sum = a, lmax = b, rmax = c; }

  49.     // t 在下面
  50.     Node operator+(const Node& t) {
  51.         return Node(sum + t.sum, max(lmax, sum + t.lmax), max(t.rmax, t.sum + rmax));
  52.     }
  53. };

  54. // SGT
  55. struct SGT {
  56.     int lc[N << 2], rc[N << 2], tot;
  57.     Node t[N << 2];

  58.     void Up(int u) { t[u] = t[lc[u]] + t[rc[u]]; }

  59.     void Build(int& u, int l, int r) {
  60.         if (!u)
  61.             u = ++tot;
  62.         if (l == r) {
  63.             // 一个点的时候 s 就是答案
  64.             t[u].sum = val[rdfn[l]];
  65.             t[u].lmax = t[u].rmax = val[rdfn[l]] + s[rdfn[l]].begin()->first;
  66.             return;
  67.         }

  68.         int mid = (l + r) >> 1;
  69.         Build(lc[u], l, mid);
  70.         Build(rc[u], mid + 1, r);
  71.         Up(u);
  72.     }

  73.     void Modify(int u, int l, int r, int p) {
  74.         if (l == r) {
  75.             t[u].sum = val[rdfn[l]];
  76.             t[u].lmax = t[u].rmax = val[rdfn[l]] + s[rdfn[l]].begin()->first;
  77.             return;
  78.         }

  79.         int mid = (l + r) >> 1;
  80.         if (p <= mid)
  81.             Modify(lc[u], l, mid, p);
  82.         if (p > mid)
  83.             Modify(rc[u], mid + 1, r, p);
  84.         Up(u);
  85.     }

  86.     Node Query(int u, int l, int r, int ql, int qr) {
  87.         if (qr < ql)
  88.             return Node(0, 0, 0);
  89.         if (ql <= l && r <= qr) {
  90.             return t[u];
  91.         }

  92.         int mid = (l + r) >> 1;
  93.         if (qr <= mid)
  94.             return Query(lc[u], l, mid, ql, qr);
  95.         if (ql > mid)
  96.             return Query(rc[u], mid + 1, r, ql, qr);
  97.         return (Query(lc[u], l, mid, ql, qr) + Query(rc[u], mid + 1, r, ql, qr));
  98.     }
  99. } sgt;

  100. void Init(int u) {
  101.     s[u].emplace(0, u);

  102.     for (auto v : e[u]) {
  103.         if (v == f[u] || v == hc[u])
  104.             continue;
  105.         // 存的是轻孩子
  106.         Init(v);
  107.         s[u].emplace(sgt.t[rt[v]].lmax, v);
  108.     }

  109.     if (hc[u])
  110.         Init(hc[u]);
  111.     else
  112.         sgt.Build(rt[L[u]], dfn[L[u]], dfn[u]);
  113. }

  114. int Query(int u) {
  115.     int res = s[u].begin()->first + val[u];
  116.     int sum = val[u], v;
  117.     Node temp;

  118.     while (u) {
  119.         // 从上往下走
  120.         temp = sgt.Query(rt[L[u]], dfn[L[u]], dfn[R[u]], dfn[u] + 1, dfn[R[u]]);
  121.         res = max(res, temp.lmax + sum);
  122.         // 从下往上走
  123.         temp = sgt.Query(rt[L[u]], dfn[L[u]], dfn[R[u]], dfn[L[u]], dfn[u] - 1);
  124.         res = max(res, temp.rmax + sum);

  125.         sum += temp.sum;

  126.         v = f[L[u]];
  127.         if (!v)
  128.             break;

  129.         // 这样写的原因是第一个点取不到
  130.         sum += val[v];
  131.         auto it = s[v].begin();
  132.         if (it->second == L[u])
  133.             it++;

  134.         res = max(res, it->first + sum);
  135.         u = v;
  136.     }

  137.     return res;
  138. }

  139. void Modify(int u, int x) {
  140.     val[u] = x;
  141.     int v, last;

  142.     // 一个点的更新会带动它上面的重链底点更新
  143.     while (u) {
  144.         v = L[u];
  145.         last = sgt.t[rt[v]].lmax;
  146.         sgt.Modify(rt[v], dfn[L[u]], dfn[R[u]], dfn[u]);

  147.         // 无法造成影响就退
  148.         if (sgt.t[rt[v]].lmax == last || v == 1) {
  149.             break;
  150.         }

  151.         s[f[v]].erase(make_pair(last, v));
  152.         s[f[v]].emplace(sgt.t[rt[v]].lmax, v);
  153.         u = f[v];
  154.     }
  155. }

  156. int main() {
  157.     ios::sync_with_stdio(0);
  158.     cin.tie(0);

  159.     freopen("lycoris.in", "r", stdin);
  160.     freopen("lycoris.out", "w", stdout);

  161.     cin >> n;
  162.     for (int i = 1; i <= n; i++) {
  163.         cin >> val[i];
  164.     }
  165.     for (int i = 1; i < n; i++) {
  166.         int u, v;
  167.         cin >> u >> v;
  168.         e[u].emplace_back(v);
  169.         e[v].emplace_back(u);
  170.     }

  171.     dfs0(1, 0);
  172.     dfs1(1, 1);
  173.     Init(1);

  174.     string op;
  175.     int x, y;

  176.     while (1) {
  177.         cin >> op;
  178.         if (op[0] == 'D') {
  179.             break;
  180.         } else if (op[0] == 'Q') {
  181.             cin >> x;
  182.             cout << Query(x) << '\n';
  183.         } else {
  184.             cin >> x >> y;
  185.             Modify(x, y);
  186.         }
  187.     }

  188.     return 0;
  189. }
复制代码

本帖被以下淘专辑推荐:

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

使用道具 举报

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

回帖奖励 +3 鱼币

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

使用道具 举报

发表于 2024-10-7 22:56:41 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

发表于 2024-11-6 18:49:15 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

发表于 2025-1-4 05:30:42 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

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

本版积分规则

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

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

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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