洛谷P1026统计单词个数题解

好久没搞dp了.jpg
题目
它康起来是个\(dp\)
我们可以设\(dp[i][j]\)表示前\(i\)个字母分成\(j\)段的单词之和最大值
\(dp\)的时候枚举新一段的断点即可
但是我们需要预处理出\([i,j]\)这一段所包含的符合条件的单词个数,设其为\(cnt[i][j]\)
因为文本串中,每个字母只能引导一个单词。为了做到这一点,我们在处理\(cnt[i][j]\)的时候倒过来进行

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
inline ll read()
{
	char ch=getchar();
	ll x=0;bool f=0;
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return f?-x:x;
}
int p,k,s,dp[209][59],cnt[409][409];
char wb[50][29],mo[8][22],wa[509];
int fd(int x,int l)
{
	for(int i=1;i<=s;i++)
	{
		int len=strlen(mo[i]+1);
		bool ok=0;
		if(len>l) continue;
		for(int j=1;j<=len;j++)
			if(mo[i][j]!=wa[x+j-1])
			{ok=1;break;}
		if(!ok) return 1;
	  // if(mo[i][1]==wa[x]) return 1;
	}
	return 0;
}
int main()
{
	p=read();k=read();
	for(int i=1;i<=p;i++)
	 scanf("%s",wb[i]+1);
	int tot=0;
	for(int i=1;i<=p;i++)
	{
		int len=strlen(wb[i]+1);
	    for(int j=1;j<=len;j++)
	     wa[++tot]=wb[i][j];
	}  
	s=read();
	for(int i=1;i<=s;i++)
		scanf("%s",mo[i]+1);
	for(int j=tot;j>=1;j--)
		for(int i=j;i>=1;i--)
			cnt[i][j]=cnt[i+1][j]+fd(i,j-i+1);
	for(int i=1;i<=k;i++) dp[i][i]=dp[i-1][i-1]+cnt[i][i];
	for(int i=1;i<=tot;i++) dp[i][1]=cnt[1][i]; 
	for(int i=1;i<=tot;i++)
	{
		for(int j=1;j<=k&&j<i;j++)
		{
			for(int l=j;l<=i-1;l++)
			{
				dp[i][j]=max(dp[i][j],dp[l][j-1]+cnt[l+1][i]);
			}
		}
	}   
	printf("%d",dp[tot][k]);
}
posted @ 2020-05-18 21:48  千载煜  阅读(169)  评论(0编辑  收藏  举报