标签:turn size har force 字典序 ace pre include main
题意:给你一个字符串,这个字符串的构造方法如下:先选择一个长度大于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\n"); return 0; } memset(dp, -1, sizeof(dp)); for (int i = 5; i <= n; i++) solve(i); set<string>::iterator it; printf("%d\n", st.size()); for (it = st.begin(); it != st.end(); it++) cout << (*it) << endl; }
标签:turn size har force 字典序 ace pre include main
原文地址:https://www.cnblogs.com/pkgunboat/p/10754282.html