题目链接
https://www.luogu.com.cn/problem/CF666A
解题思路
居然是dp。
提醒:twice in a row译为 连续两次
dp[i][2]=1表示(i,i+1)满足条件,=0表示不满足;
dp[i][3]=1表示(i,i+1,i+2)满足条件,=0表示不满足。
转移方程:
如果(i,i+1)==(i+2,i+3),dp[i][2]=dp[i+2][3] //含义为如果连续两个长度为2的子字符串相等,那么要能选起始地址小的长度为2的子字符串,就只能由与之相连的长度为3的子字符串转移过来,只有这个长度为3的子字符串满足,接下来的这个子串才能被选。 如果(i,i+1)!=(i+2,i+3),dp[i][2]=dp[i+2][2] || dp[i+2][3] //含义为如果连续两个长度为2的子串不相等,那么判断起始地址小的长度为2的子串是否满足,既可以由与之相连的长度为2的子串转移,也可以由长度为3的转移。 如果(i,i+1,i+2)==(i+3,i+4,i+5),dp[i][3]=dp[i+3][2] //理解同上 如果(i,i+1,i+2)==(i+3,i+4,i+5),dp[i][3]=dp[i+3][2] || dp[i+3][3] //理解同上
AC代码
#include<bits/stdc++.h> using namespace std; const int N=1e4+10; int dp[N][5],n; set<string> ans; string s; int main() { cin>>s; n=s.size(); s='.'+s; if(n<=6) puts("0"); else { dp[n+1][2]=dp[n+1][3]=1;//初始化,转移边界 for(int i=n-1;i>5;i--) { if(i<=n-3) dp[i][2]=(s.substr(i,2)==s.substr(i+2,2)?0:dp[i+2][2]) || dp[i+2][3]; else dp[i][2]=dp[i+2][2]; if(i<=n-5) dp[i][3]=(s.substr(i,3)==s.substr(i+3,3)?0:dp[i+3][3]) || dp[i+3][2]; else dp[i][3]=dp[i+3][2] || dp[i+3][2]; if(dp[i][2]) ans.insert(s.substr(i,2)); if(dp[i][3]) ans.insert(s.substr(i,3)); } cout<<ans.size()<<endl; for(set<string>::iterator it=ans.begin();it!=ans.end();it++) cout<<*it<<endl; } return 0; }
总结
twice in a row 这个短语,某度翻译都没翻译出来,还是单独翻译这个短语才翻译出来的,因为以为只要重复就要停,所以直接dfs了,9的时候T了。
看题解发现了盲点,是dp,看了思路,自己调通了。