Day-7 模拟赛题解
T1
数据点 3 - 5
- 枚举每一个问号对应的字母
- Kmp,把 s 当作模式串匹配 T
,k 是 ? 的个数
代码(我也不知道为啥 T 了,鸽着)
正解
- 有种被诈骗了的感觉
- 根据期望的可加性,答案等于各个字符串出现次数的期望的和
- 于是,各个字符串出现在哪里相互没有关联
- 于是,枚举每个字符串出现的位置,单独计算期望,累加
- 设字符串 S = T[i, j] 中有
个 ?,则他的期望 = - 复杂度
,所以枚举起点 ,每个起点每个 S 都访问一次 ,相乘- 这是一个均摊复杂度
- 注:string 超级慢!! 用 char 不容易被卡
代码
# include <bits/stdc++.h> # define int long long # define double long double using namespace std; const int MOD = 998244353; const int N = (int)5e3 + 10; int q, n; int poww[N]; char s[N], t[N]; int Q_pow(int a, int b){ int ans = 1, p = a; while(b){ if(b & 1){ ans = (ans * p) % MOD; } b >>= 1; p = (p * p) % MOD; } return ans; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int up = 5000; poww[0] = 1; for(int i = 1; i <= up; i++){ poww[i] = poww[i - 1] * 26 % MOD; } cin >> q; while(q--){ cin >> t >> n; int k = 0; for(auto i : t){ if(i == '?'){ k++; } } int len = strlen(t), ans = 0; for(int i = 1; i <= n; i++){ cin >> s; int lenn = strlen(s), up = len - lenn + 1; for(int j = 0; j < up; j++){ bool f = 1; int temp = k; for(int k = 0; k < lenn; k++){ if(t[j + k] != '?' && s[k] != t[j + k]){ f = 0; break; } if(t[j + k] == '?'){ temp--; } } if(f == 1){ ans = (ans + poww[temp]) % MOD; } } } ans = ans * Q_pow(poww[k], MOD - 2) % MOD; cout << ans << "\n"; } }
T2
-
均摊时间复杂度坑爹啊!
- 每组数字只会被加进去 && 删除 1 次,均摊
- 而我费尽心思线段树 + 二分加上去两个 log
- 每组数字只会被加进去 && 删除 1 次,均摊
-
设原来拼成的数字是 c (考虑操作带来的影响)
- 加入:
- 删除:
- len 为 c 的长度,
为 x 个 y 构成的数
- 加入:
-
如何求
- 小学奥数
-
对于
,常规方法是快速幂,但是 5e6 带 log 跑不过- 光速幂
光速幂
-
能做到单次询问
-
对于
,设 -
则
-
我们要做的就是预处理
- 当
时预处理为 ,时间复杂度最小 - 预处理出
时的 ,在 1e4 - 1e5 级别
- 当
-
根据欧拉定理
,这可以缩小 b 的范围到 [0, mod] 中 -
完事!
代码
- 出题人卡我输入输出!!
- 不过快读是真快!!
# include <bits/stdc++.h> # define int long long # define double long double using namespace std; const int INV = 443664157; // INV 9 const int MOD = 998244353; const int N = (int)1e7 + 10; int n; int opt, x, y; struct Node{ int x, y; }a[N]; int l, r, val, len; int read(){ int sum=0,f=1;char st=getchar(); while(st<'0'||st>'9'){ if(st=='-')f=-1; st=getchar(); } while('0'<=st&&st<='9'){ sum=(sum<<3)+(sum<<1)+st-'0'; st=getchar(); } return sum*f; } int p, phi, base = 10, pw[N][2]; int Phi(int x){ int ans = x; for(int i = 2; i * i <= x; i++){ if(x % i == 0){ ans = ans / i * (i - 1); while(x % i == 0){ x /= i; } } } if(x > 1){ ans = ans / x * (x - 1); } return ans; } void Init(){ phi = Phi(MOD); p = sqrt(MOD); pw[0][0] = pw[0][1] = 1; for(int i = 1; i <= p; i++){ pw[i][0] = pw[i - 1][0] * base % MOD; } for(int i = 1; i <= p; i++){ pw[i][1] = pw[i - 1][1] * pw[p][0] % MOD; } } int Query(int b){ b %= phi; return pw[b % p][0] * pw[b / p][1] % MOD; } signed main(){ n = read(); Init(); l = r = val = len = 1; a[1] = {1, 1}; for(int i = 1; i <= n; i++){ opt = read(); if(opt == 1){ x = read(), y = read(); a[++r] = {x, y}; len += x; val = (val * Query(x) % MOD + y * (Query(x) + MOD - 1) % MOD * INV % MOD) % MOD; }else if(opt == 2){ x = read(); while(x){ if(x >= a[l].x){ val = val + MOD - a[l].y * (Query(a[l].x) + MOD - 1) % MOD * INV % MOD * Query(len - a[l].x) % MOD; val %= MOD; x -= a[l].x; len -= a[l].x; l++; }else{ val = val + MOD - a[l].y * (Query(x) + MOD - 1) % MOD * INV % MOD * Query(len - x) % MOD; val %= MOD; a[l].x -= x; len -= x; x = 0; } } }else{ printf("%lld\n", val); } } }
T3
- 只写 60 分做法,满分做法太阴间了,鸽了
- 设 dp[i][j] 表示 i 节点及其子树原来无色,强行染成 j 色后还需要几步达到题目要求
- 对于节点 i,
- 如果
,dp[i][j] = mini - 否则,dp[i][j] = mini + 1
- 即:先用 1 步把 i 及其子树染成 j,再一股脑染成 mini 对应的颜色
- 这样比 mini 多用 1 步
- 如果
- 注:全局定义的数组在递归中调用时要注意
- 不要 i 调用了又在
调用(除非需要这么做)
- 不要 i 调用了又在
代码
# include <bits/stdc++.h> # define int long long # define double long double using namespace std; const int N = 5e3 + 10; int n; int fa, a[N]; int maxc, sumc[N], dp[N][N]; vector <int> e[N]; void Dfs(int x){ if(a[x] != 0){ for(int i = 0; i <= maxc; i++){ dp[x][i] = (a[x] != i); } }else{ for(auto i : e[x]){ Dfs(i); } for(int i = 0; i <= maxc; i++){ sumc[i] = 0; } for(auto i : e[x]){ for(int j = 0; j <= maxc; j++){ sumc[j] += dp[i][j]; } } int mini = (int)1e18; for(int i = 0; i <= maxc; i++){ mini = min(mini, sumc[i]); } for(int i = 0; i <= maxc; i++){ if(sumc[i] == mini){ dp[x][i] = mini; }else{ dp[x][i] = mini + 1; } } } } signed main(){ cin >> n; for(int i = 2; i <= n; i++){ cin >> fa; e[fa].push_back(i); } for(int i = 1; i <= n; i++){ cin >> a[i]; maxc = max(maxc, a[i]); } Dfs(1); cout << dp[1][0] << "\n"; }
T4
- 鸽了
分类:
集训 / 24寒假-mx
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话