题目链接:https://www.luogu.org/problemnew/show/P1470
这道题就是类似完全背包和N^2的LIS的思想,如果连背包和LIS都没学过的可以百度DD大牛的背包9讲和LIS,都是很经典的DP模型,再回来看这题应该就能迎刃而解了。
然后再掌握了基本背包思想后回到来看这一题的思路,就是先把所以的模式串P都存起来,之后我们逐个对i位置尝试该位置能不能放任意一个模式串,能的话就把dp[i]标记为1,当然还要先查看dp[i-模式串长度]为不为1,如果你前面都匹配不上了,后面这里匹配上了也没有用,毕竟要找的是最长连续能匹配的。
已经很多大佬把思路讲的很好了,这里就是随便再写写,代码也自认还算清晰,然后主要发这篇文章的原因是想提醒大家注意两个坑点,第一个就是边界问题,这里i的边界是需要<=而不是<字符串长度的,第一次习惯性没加=然后一个数据WA了(这里自行思考一下为什么,应该是很简单的)。
第二个坑点跟这题无关,算C++方面的,就是size_type类型跟int类型做运算后要强制类型转换,不如会出现奇怪的BUG,例如我第一次没做强制类型转换就发现if怎么样都能进去,输出又是正确的(因为输出时的%d也算做了转换)
下面附上一下AC代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
using namespace std;
set<string> p;
int dp[200005]={0};
int main()
{
ios::sync_with_stdio(false);
string pi;
while(cin>>pi&&pi!=".")
{
p.insert(pi);
}
string s;
while(cin>>pi)
{
s+=pi;
}
dp[0]=1;
//注意i的边界是<=size()
for(int i=1;i<=s.size();i++)//理论上来说这里的size()最好也先取出来,一是省常数时间,二是避免玄学BUG
{
for(set<string>::iterator it=p.begin();it!=p.end();it++)
{
string tmp=(*it);
if((int)(i-tmp.size())>=0)//size_type类型做运算要强制转换,以免出现玄学BUG
{
if(dp[i-tmp.size()]&&tmp==s.substr(i-tmp.size(),tmp.size()))//类完全背包思想
{
dp[i]=1;
}
}
}
}
//注意i的边界是=size()
for(int i=s.size();i>=0;i--)
{
if(dp[i])
{
printf("%d",i);
return 0;
}
}
return 0;
}