CF666A Reberland Linguistics

题目链接

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,看了思路,自己调通了。

dp 文章被收录于专栏

全部评论

相关推荐

1 收藏 评论
分享
牛客网
牛客企业服务