鱼C论坛

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

[心之碎片] - 20240816模拟赛

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

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

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

x
本帖最后由 柿子饼同学 于 2024-8-16 21:58 编辑
总结与反思
ll = 1ll * int * int
取模要看好了, 不要把 ans 也乘了
一定要会打部分分!
A - 考虑条件的限制有什么巧方法水过去, 而不是一来就想高级算法
B - 中缀表达式求值要会
C - EXgcd 要更熟练一点
D - 计数题一定要有组合思想, 分类要细致, dfs 相关(做差, 栈, 树上差分) 之类的简单算法要先想, 树上路径其实是点



P7229 [COCI2015-2016#3] SLON
B 的 dfs 求中缀表达式
  1. int dfs() {
  2.     int res = 0, cur = 1, temp = 0;

  3.     for (; s[pos] != ')' && s[pos]; pos++) {
  4.         if (s[pos] == '(') {
  5.             pos++;
  6.             temp = dfs();
  7.         } else if (isdigit(s[pos]) || s[pos] == 'x') {
  8.             temp = temp * 10 + mp[s[pos]];
  9.             temp %= m;
  10.         } else {
  11.             cur = 1ll * cur * temp % m;
  12.             temp = 0;

  13.             if (s[pos] != '*')
  14.                 res = (res + cur + m) % m;
  15.             if (s[pos] == '-')
  16.                 cur = -1;
  17.             if (s[pos] == '+')
  18.                 cur = 1;
  19.         }
  20.     }

  21.     cur = 1ll * cur * temp % m;
  22.     return (res + cur + m) % m;
  23. }
复制代码


C - P4031 [Code+#2] 可做题2
没啥可说的, 之前想的是枚举最后的 [l, r], 后来发现可以数论分块...
  1. #include <bits/stdc++.h>
  2. using namespace std;

  3. typedef long long ll;

  4. ll T, a1, l, r, k, p, m;

  5. struct Matrix {
  6.     ll mat[2][2];

  7.     Matrix() { memset(mat, 0, sizeof(mat)); }

  8.     Matrix operator*(const Matrix& t) const {
  9.         Matrix temp;
  10.         for (int k = 0; k < 2; k++) {
  11.             for (int i = 0; i < 2; i++) {
  12.                 for (int j = 0; j < 2; j++) {
  13.                     temp.mat[i][j] += mat[i][k] * t.mat[k][j] % p;
  14.                     temp.mat[i][j] %= p;
  15.                 }
  16.             }
  17.         }
  18.         return temp;
  19.     }
  20. } base;

  21. ll Exgcd(ll a, ll b, ll& x, ll& y) {
  22.     if (!b) {
  23.         x = 1, y = 0;
  24.         return a;
  25.     }

  26.     ll x1, y1;
  27.     ll d = Exgcd(b, a % b, x1, y1);
  28.     x = y1, y = x1 - a / b * y1;

  29.     return d;
  30. }

  31. Matrix qp(Matrix a, ll b) {
  32.     Matrix res;
  33.     for (int i = 0; i < 2; i++) res.mat[i][i] = 1;

  34.     while (b) {
  35.         if (b & 1)
  36.             res = res * a;
  37.         a = a * a;
  38.         b >>= 1;
  39.     }

  40.     return res;
  41. }

  42. int main() {
  43.     ios::sync_with_stdio(0);
  44.     cin.tie(0);

  45.     freopen("fib.in", "r", stdin);
  46.     freopen("fib.out", "w", stdout);

  47.     base.mat[0][0] = base.mat[0][1] = base.mat[1][0] = 1;

  48.     cin >> T;
  49.     while (T--) {
  50.         cin >> a1 >> l >> r >> k >> p >> m;

  51.         a1 %= p;
  52.         auto cur = qp(base, k - 1);

  53.         ll ka1 = a1 * cur.mat[1][1] % p;
  54.         ll ka2 = cur.mat[0][1] % p;
  55.         ll gcd = __gcd(ka2, p);

  56.         // ak = ka1 + ka2*a2
  57.         // 得到不定方程:
  58.         // ka2*x + p*y = m - ka1
  59.         // A*x + B*y = C

  60.         if ((m - ka1) % gcd) {
  61.             cout << "0\n";
  62.             continue;
  63.         }

  64.         ll A = ka2 / gcd, B = p / gcd, C = (m - ka1) / gcd;
  65.         ll x, y, d;

  66.         d = Exgcd(A, B, x, y);

  67.         x = (x * C % B + B) % B;
  68.         // x 是最小正整数解, x*a2 + ka1 = ak

  69.         if (x > r) {
  70.             cout << "0\n";
  71.         } else {
  72.             if (l <= x) {
  73.                 cout << (r - x) / B + 1 << '\n';
  74.             } else {
  75.                 cout << (r - x) / B - (l - 1 - x) / B << '\n';
  76.             }
  77.         }
  78.     }

  79.     return 0;
  80. }
复制代码


D - 树上路径交
知知有一棵n个节点的树,根节点为1,树上每条边长度为1,定义G路径是连接祖先节点和其子孙节点的路径。
她想要知道有多少对路径的路径交是长度在 [L, R] 之间的G路径。

首先想到枚举交的部分, 然后一上一下每个点求一个不在同一个子树里取两个点的方案数
然后这里相当于利用 dfs 栈批量处理了

  1. typedef long long ll;

  2. const int N = 3e6 + 5;
  3. const ll P = 1e9 + 7;

  4. int n, l, r;
  5. // up[i], 除了 i 这个子树和她的父节点, 在剩余子树中选择两个点使得不在同一个子树的方案数
  6. // dn[i], i 这个子树, 选择 2 个点使得不在同一子树的方案数(不包括 i)
  7. ll up[N], dn[N], dep[N], siz[N], ans;
  8. vector<int> e[N];

  9. void dfs0(int u) {
  10.     siz[u] = 1;

  11.     for (auto v : e[u]) {
  12.         dfs0(v);
  13.         siz[u] += siz[v];
  14.     }

  15.     ll temp = 1ll * n * (n - 1) / 2;
  16.     dn[u] = 1ll * siz[u] * (siz[u] - 1) / 2;

  17.     for (auto v : e[u]) {
  18.         // 强制减去两个点都在 v 子树的方案
  19.         dn[u] -= siz[v] * (siz[v] - 1) / 2;
  20.         temp -= siz[v] * (siz[v] - 1) / 2;
  21.     }

  22.     dn[u] %= P;
  23.     temp -= (n - siz[u]) * (n - siz[u] - 1) / 2;

  24.     for (auto v : e[u]) {
  25.         // 上面已经减过重复情况了, 这里只需要减掉一个点在 v 子树内的方案数
  26.         up[v] = temp - (n - siz[v]) * siz[v];
  27.     }
  28. }

  29. ll stk[N];
  30. int top;

  31. void dfs(int u) {
  32.     if (u != 1) {
  33.         top++;
  34.         stk[top] = (stk[top - 1] + up[u]) % P;

  35.         if (top >= l) {
  36.             // sum 是指这一区间内的点上方选取 2 个不在同子树的点的方案数
  37.             ll sum = ((stk[top - l + 1] - stk[max(0, top - r)]) % P + P) % P;

  38.             // u 的子节点和这些点的上方节点, *2 是因为有 2 种情况, a, b -- c, d , a 可以选 c 也可以选 d
  39.             ans = (ans + 2 * sum % P * dn[u] % P) % P;

  40.             // u 的子节点和这些点(相同结尾 都是在这个区间内的点)
  41.             ans = (ans + (min(top, r) - l + 1) * dn[u] % P) % P;

  42.             // u 自己和这些点(相同起点 u)
  43.             ans = (ans + sum) % P;
  44.         }
  45.     }

  46.     for (auto v : e[u]) {
  47.         dfs(v);
  48.     }

  49.     if (u != 1) {
  50.         top--;
  51.     }
  52. }
复制代码

本帖被以下淘专辑推荐:

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

使用道具 举报

发表于 2024-8-17 12:25:45 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

发表于 2024-8-17 16:44:24 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

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

回帖奖励 +3 鱼币

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

使用道具 举报

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

回帖奖励 +3 鱼币

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

使用道具 举报

发表于 2024-8-19 15:07:15 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

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

使用道具 举报

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

回帖奖励 +3 鱼币

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

使用道具 举报

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

回帖奖励 +3 鱼币

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

使用道具 举报

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

回帖奖励 +3 鱼币

我看的是高手成长阶梯啊!
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

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

回帖奖励 +3 鱼币

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

使用道具 举报

发表于 2024-9-5 00:39:50 | 显示全部楼层

回帖奖励 +3 鱼币

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

使用道具 举报

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

本版积分规则

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

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

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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