Codeforces Round 811 (Div. 3)

1|0基本情况

ABC秒了。

DE都给了我希望,但都做不下去。

两道题反复横跳,结果最后谁也没做出来。

E还是比D亲切的,先补E吧。

2|0E. Add Modulo 10

做的时候想着说对每个个位数的变化找找规律,但是没有进一步的发现。

实际上就应该从这里下手。

首先共识:相同的两个数经过操作后必然相同。

分析每一个十进制末位,即数经过一次变换后末位会从啥变成啥:

由图得 {a} 中不能同时存在 5 的倍数和非 5 的倍数。

若全为 5 的倍数,将她们的末尾全部操作为 0,判断相等即可。

若全非 5 的倍数,将她们的末尾全部操作为 2。由于 24862 绕一圈后原数会 +20,所以我们判断这些数是否 mod 20 同余即可。

#include<iostream> #include<algorithm> #include<cstdio> const int N = 2e5 + 10; int n, a[N]; void calc(int& x) {while(x % 10 != 2 && x % 10 != 0) x += x % 10;} void solve() { std::cin >> n; for (int i = 1; i <= n; i++) std::cin >> a[i]; int cnt = 0; for (int i = 1; i <= n; i++) if (a[i] % 5 == 0) cnt++; if (cnt > 0 && cnt < n) {std::cout << "NO\n"; return ;} for (int i = 1; i <= n; i++) calc(a[i]); if(!cnt) for (int i = 1; i <= n; i++) a[i] %= 20; for (int i = 2; i <= n; i++) if(a[i] != a[i - 1]) {std::cout << "NO\n"; return ;} std::cout << "YES\n"; } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); int _; std::cin >> _; while(_--)solve(); return 0; }

3|0D. Color with Occurrences

做的时候真的毫无想法。

没想到居然是DP,想必我知道了是DP也做不出来的


由于同一段可以被染色多次,所以最小代价和顺序无关。

可以想到动态规划,设 dp[i] 为将 t 的前 i 个字符都染色的最小代价。

考虑如何进行转移,不妨预处理出 lenj 表示 sj 的长度, match[i][j] 表示 sj 能否匹配字符串 t 中以位置 i 结尾,长度为 lenj 的子串。这样就很好转移,对于每个位置 i,考虑每个能够匹配的 sj,对于每个 sj,从 [ilenj,i] 区间内转移。注意:由于染色区间可以不交,所以左端点为 ilenj 而不是 ilenj+1。由此得到状态转移方程如下:

dp[i]=minmatch[i][j]=1{mink=ilenjidp[k]+1}

在转移的同时记录 from[i]type[i] 数组,记录转移到 i 的状态的染色终点(即方程中的 k)和染色时使用的模板串编号(即方程中的 j)。

注意 dp 数组初值应为正无穷,若转移完后 dp[n]=,则报告无解,否则使用记录的 from[i]type[i] 递归输出方案即可。单组数据时间复杂度 O(|t||si|),可以通过。参考代码如下:

#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> const int N = 110; int dp[N], from[N], ok[N][N]; int len[N], type[N]; std::string s; void print(int n) { if (n == 0) return; print(from[n]); std::cout << type[n] << " " << n - len[type[n]] + 1 << std::endl; return ; } void init() { std::cin >> s; memset(dp, 0x3f, sizeof(dp)); memset(from, 0, sizeof(from)); memset(ok, 0, sizeof(ok)); dp[0] = 0; } void solve() { init(); int n = s.length(), m; std::cin >> m; s='0'+s; for (int i = 1; i <= m; i++) { std::string temp; std::cin >> temp; len[i] = temp.length(); for (int j = len[i]; j <= n; j++) { if (s.substr(j - len[i] + 1, len[i]) == temp) ok[j][i] = 1; } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (!ok[i][j]) continue; for (int k = i - len[j]; k < i; k++) { if (dp[k] + 1 < dp[i]) { from[i] = k, type[i] = j; dp[i] = dp[k] + 1; } } } } if (dp[n] == 0x3f3f3f3f) std::cout << -1 << std::endl; else std::cout << dp[n] << std::endl, print(n); } int main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); int _; std::cin >> _; while(_--) solve(); return 0; }

__EOF__

本文作者Kdlyh
本文链接https://www.cnblogs.com/kdlyh/p/17891194.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   加固文明幻景  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示