您的位置:首页 > 博客中心 > 互联网 >

Codeforces 667C DP

时间:2022-05-07 19:41

题意:给你一个字符串,这个字符串的构造方法如下:先选择一个长度大于4的前缀,然后每次向字符串尾部添加一个长度为2或者长度为3的后缀,不能添加连续的相同的后缀,问可能的后缀有哪些?并按字典序输出去。

思路:第一眼感觉要记忆化,设dp[i]表示把前i个字符作为前缀是否有合法方案,那么只有当前长度为2的串和后面的串重复了,长度为3的串和后面的串重复了,并且dp[i + 5]不合法,dp[i]才不合法。为什么呢?考虑这样一个样例: abcdezzzzzzzz, 合法的后缀有zz 和zzz, 我们可以让zz 和zzz交替出现。

代码:

#include 
using namespace std;
const int maxn = 10010;
int dp[maxn];
set 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\n");
		return 0;
	}
	memset(dp, -1, sizeof(dp));
	for (int i = 5; i <= n; i++)
		solve(i);
	set::iterator it;
	printf("%d\n", st.size());
	for (it = st.begin(); it != st.end(); it++)
		cout << (*it) << endl;
} 

  

本类排行

今日推荐

热门手游