Codeforces 667C DP
Posted pkgunboat
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 667C DP相关的知识,希望对你有一定的参考价值。
题意:给你一个字符串,这个字符串的构造方法如下:先选择一个长度大于4的前缀,然后每次向字符串尾部添加一个长度为2或者长度为3的后缀,不能添加连续的相同的后缀,问可能的后缀有哪些?并按字典序输出去。
思路:第一眼感觉要记忆化,设dp[i]表示把前i个字符作为前缀是否有合法方案,那么只有当前长度为2的串和后面的串重复了,长度为3的串和后面的串重复了,并且dp[i + 5]不合法,dp[i]才不合法。为什么呢?考虑这样一个样例: abcdezzzzzzzz, 合法的后缀有zz 和zzz, 我们可以让zz 和zzz交替出现。
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 10010; int dp[maxn]; set<string> st; char s[maxn]; int n; bool match(int s1, int s2, int cnt) { for (int i = 0; i < cnt; i++) { if(s[s1 + i] != s[s2 + i]) return 0; } return 1; } int solve(int i) { if(i > n) return 0; if(dp[i] != -1) { return dp[i]; } if(i == n) { dp[n] = 1; return 1; } dp[i] = 0; if(i + 2 <= n) { if(solve(i + 2)) { if((i <= n - 3 && match(i + 1, i + 2 + 1, 2)) && !solve(i + 5)) { dp[i] |= 0; } else { dp[i] |= 1; string tmp = ""; tmp += s[i + 1]; tmp += s[i + 2]; st.insert(tmp); } } } if(i + 3 <= n) { if(solve(i + 3)) { if((i <= n - 5 && match(i + 1, i + 3 + 1, 3)) && !solve(i + 5)) { dp[i] |= 0; } else { dp[i] |= 1; string tmp = ""; tmp += s[i + 1]; tmp += s[i + 2]; tmp += s[i + 3]; st.insert(tmp); } } } return dp[i]; } int main() { scanf("%s",s + 1); n = strlen(s + 1); if(n <= 5) { printf("0 "); return 0; } memset(dp, -1, sizeof(dp)); for (int i = 5; i <= n; i++) solve(i); set<string>::iterator it; printf("%d ", st.size()); for (it = st.begin(); it != st.end(); it++) cout << (*it) << endl; }
以上是关于Codeforces 667C DP的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 86C Genetic engineering(AC自动机+DP)
CodeForces 1005D Polycarp and Div 3(思维贪心dp)
Codeforces Round #267 (Div. 2) C. George and Job
代码源 Div1#104no crossing,Codeforces 793D,2100分,区间dp
[Codeforces Round #522 (Div. 2, based on Technocup 2019 Elimination Round 3)][C. Playing Piano](代码片段