发在讨论版的原因就是因为不想写题解,格式太麻烦了,况且也不怎么会用markdown
我们明确的是O(∣S∣2)的算法肯定是过不去的,我又不想写优化(其实就是不会),那么为什么不考虑换个状态转移的方式呢?
首先,我们先观察数据范围,集合中的每个元素的长度不超过10?这不就是一个突破口吗?
dp[i]表示前缀长度为i 时,能否被分解
那我们怎么更新后面的状态呢?很简单,当dp[i]==1时,说明前i 个字符肯定能被分解,前面就不用管了,我们只需要知道后面的字符能不能被更新就可以了:
若s[i]到s[i+j],这一段字串在集合中,那么dp[i+j]便可更新为1,好懂吧
时间复杂度为O(∣S∣∗k∗logk) ,k 是最长的元素串的长度,判断字符串是否在集合中存在,用的是map,因此要乘 logk ,过这道题绰绰有余
以下是代码:
#include<iostream>
#include<map>
#include<cmath>
using namespace std;
const int MAXN=2e5+5;
string t,s;
int Max,ans,len;
map<string,bool> mp;
bool dp[MAXN];
int main(){
ios_base::sync_with_stdio(0);
while( cin>>t ){
if( t=="." )
break;
mp[t]=1;
len=t.size();
Max=max(Max,len);
}
while( cin>>t )
s+=t;
len=s.size();
dp[0]=1;
for(int i=0;i<=len;i++){
if( !dp[i] )
continue;
t="";
for(int j=1;j<=min(Max,len-i);j++){
t+=s[i+j-1];
if( mp[t] )
dp[i+j]=1;
}
}
for(ans=len;ans>=0;ans--)
if( dp[ans] )
break;
printf("%d",ans);
return 0;
}