关于这道题的一个正确做法
查看原帖
关于这道题的一个正确做法
538427
czy0323楼主2022/10/8 22:44

发在讨论版的原因就是因为不想写题解,格式太麻烦了,况且也不怎么会用markdown

我们明确的是O(S2)O(|S|^2)的算法肯定是过不去的,我又不想写优化(其实就是不会),那么为什么不考虑换个状态转移的方式呢?

首先,我们先观察数据范围,集合中的每个元素的长度不超过10?这不就是一个突破口吗?

dp[i]dp[i]表示前缀长度为ii 时,能否被分解

那我们怎么更新后面的状态呢?很简单,当dp[i]dp[i]==1时,说明前ii 个字符肯定能被分解,前面就不用管了,我们只需要知道后面的字符能不能被更新就可以了:

s[i]s[i]s[i+j]s[i+j],这一段字串在集合中,那么dp[i+j]dp[i+j]便可更新为1,好懂吧

时间复杂度为O(Sklogk)O(|S|*k*logk)kk 是最长的元素串的长度,判断字符串是否在集合中存在,用的是map,因此要乘 logklogk ,过这道题绰绰有余

以下是代码:

#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;
}
2022/10/8 22:44
加载中...