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](代码片段

CodeForces 735E(树形DP)