Codeforces Round 972 (Div. 2)
C. Lazy Narek (C)#
\(dp[i][j]\) 表示到第 \(i\) 个字符串为止、以"narek"中第 \(j\) 个字母结尾时的最大得分,预处理每个字符串从第 \(j\) 个字母开始统计所得的最大长度,暴力转移即可,时间复杂度 \(O(25n)\). vp的时候由于中途花了半小时选课、没调完这题,不好评价。
const int N = 1e3 + 10, INF = 1e9; char c[N][N], a[5] = {'n', 'a', 'r', 'e', 'k'}; int sum[N], cnt[N][5], dp[5][2]; void solve() { int n, m; scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%s", c[i] + 1); sum[i] = 0; for(int j = 0; j < 5; j++) { cnt[i][j] = 0; int pre = (j + 4) % 5; for(int k = 1; k <= m; k++) { if(c[i][k] == a[j]) sum[i]++; if(c[i][k] == a[(pre + 1) % 5]) { pre = (pre + 1) % 5; cnt[i][j]++; } } } } int it = 1; for(int j = 1; j < 5; j++) dp[j][it] = -INF; dp[0][it] = 0; for(int i = 1; i <= n; i++) { it ^= 1; for(int j = 0; j < 5; j++) { dp[j][it] = dp[j][it ^ 1]; } for(int j = 0; j < 5; j++) { for(int k = 0; k < 5; k++) { //printf("cnt[%d] = %d\n", k, cnt[i][k]); int d = j - k; if(d < 0) d += 5; if(d > cnt[i][k] || cnt[i][k] == 0) continue; int to = ((cnt[i][k] - d) % 5 + j) % 5; dp[to][it] = max(dp[to][it], dp[j][it ^ 1] + (cnt[i][k] - d) - (sum[i] - cnt[i][k] + d)); //printf("j = %d, to = %d, ori = %d, dp = %d\n", j, to, dp[j][it ^ 1], dp[to][it]); } } } int ans = 0; for(int j = 0; j < 5; j++) { ans = max(ans, dp[j][it] - j * 2); } printf("%d\n", ans); }
D. Alter the GCD (D)#
一个妙妙小结论:对于一个序列 \(a\),其所有前缀的gcd最多只有 \(\log a_{max}\) 个。用st表维护区间gcd,暴力枚举 \(1\) 至 \(n\) 作为左端点 \(l\),只有当 \(gcd(l, r)\) 或 \(gcd(r + 1, n)\) 发生变化时,才有可能出现新的答案,二分查找即可。
为什么没有代码呢?因为我的代码TLE了,并且官方题解太复杂没看懂,于是被迫放弃
E1. Subtangle Game (Easy Version) (E1)#
首先有一个贪心的结论:若矩阵中存在多个 \((i, j) = a\),选择最接近 \((n, m)\) 的元素、使剩余矩阵中不存在 \(a\) 是最优的。(假设远离 \((n, m)\) 的某个 \((x, y)\) 与当前 \((i, j)\) 之间存在对下一轮选择更有利的位置,对手也可以使其无法选择。)因此 \(a\) 序列中重复出现的数字、及其之后的所有数实际上是无效的,由 \(a_i\leq 7\) 可得有效数字最多只有 \(7\) 个,考虑dp,\(dp[i][j][k]\) 表示对序列中第 \(i\) 个数、在 \((j, k)\) 至 \((n, m)\) 的子矩阵中先手操作的胜负情况。该状态可由 \(dp[i][j - 1][k],dp[i][j][k - 1]\)(必胜态)或 \(dp[i][j - 1][k - 1]\)(必败态)转移而来,根据博弈论规则计算即可。
void solve() { int l, n, m; scanf("%d%d%d", &l, &n, &m); for(int i = 1; i <= l; i++) { scanf("%d", &a[i]); } for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { scanf("%d", &b[i][j]); } } int l1 = l; set <int> s; for(int i = 1; i <= l; i++) { if(s.count(a[i])) { l1 = i - 1; break; } s.insert(a[i]); } for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { for(int k = 1; k <= l1; k++) { dp[k][i][j] = 0; } } } for(int k = l1; k; k--) { for(int i = n; i; i--) { for(int j = m; j; j--) { if(i < n && dp[k][i + 1][j]) dp[k][i][j] = 1; if(j < m && dp[k][i][j + 1]) dp[k][i][j] = 1; if(b[i][j] == a[k]) { if(i == n || j == m || k == l1 || dp[k + 1][i + 1][j + 1] == 0) dp[k][i][j] = 1; } } } } if(dp[1][1][1]) printf("T\n"); else printf("N\n"); }
E2. Subtangle Game (Hard Version) (E2)#
E1的状态转移在E2显然会TLE,考虑对原dp方程进行优化,将第一维的信息转到dp值中;具体地,令 \(dp[i][j]\) 表示使 \((i, j)\) 到 \((n, m)\) 子矩阵先手必胜的最长后缀起点。乍一看非常奇怪,但这和博弈论从终局向前推理的逻辑是一致的。对于不同的起点位置,其先后手顺序会发生变化,因此维护两个dp数组分别记录起点(在 \(a\) 序列中)为奇数/偶数的情况。若奇数情况下 \(dp[1][1] = 1\) 成立,则先手必胜,反之必败。
void solve() { int l, n, m; scanf("%d%d%d", &l, &n, &m); for(int i = 1; i <= l; i++) { scanf("%d", &a[i]); } for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { scanf("%d", &b[i][j]); } } for(int i = 1; i <= n + 1; i++) { for(int j = 1; j <= m + 1; j++) { f[i][j] = g[i][j] = INF; } } fill(id + 1, id + n * m + 1, 0); for(int i = 1; i <= l; i++) { if(id[a[i]]) { l = i - 1; break; } id[a[i]] = i; } for(int i = n; i; i--) { for(int j = m; j; j--) { // 常规转移 g[i][j] = min(g[i + 1][j], g[i][j + 1]); f[i][j] = min(f[i + 1][j], f[i][j + 1]); if(!id[b[i][j]]) continue; // 偶数情况,奇数必胜态在至少3步后,此时操作则奇数必败 if((id[b[i][j]] & 1) == 0 && id[b[i][j]] + 3 <= g[i + 1][j + 1]) { f[i][j] = min(f[i][j], id[b[i][j]]); } // 奇数情况同理 if((id[b[i][j]] & 1) && id[b[i][j]] + 3 <= f[i + 1][j + 1]) { g[i][j] = min(g[i][j], id[b[i][j]]); } } } if(g[1][1] == 1) printf("T\n"); else printf("N\n"); }
作者:Aderose_yr
出处:https://www.cnblogs.com/meowqwq/p/18429954
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
喵喵喵)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】