P1026

[NOIP2001 提高组] 统计单词个数

题目描述

给出一个长度不超过 \(200\) 的由小写英文字母组成的字母串(该字串以每行 \(20\) 个字母的方式输入,且保证每行一定为 \(20\) 个)。要求将此字母串分成
\(k\) 份,且每份中包含的单词个数加起来总数最大。

每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串 this 中可包含 this 和 is,选用 this 之后就不能包含
th。

单词在给出的一个不超过 \(6\) 个单词的字典中。

要求输出最大的个数。

输入格式

每组的第一行有两个正整数 \(p,k\)。
\(p\) 表示字串的行数,\(k\) 表示分为 \(k\) 个部分。

接下来的 \(p\) 行,每行均有 \(20\) 个字符。

再接下来有一个正整数 \(s\),表示字典中单词个数。
接下来的 \(s\) 行,每行均有一个单词。

输出格式

\(1\)个整数,分别对应每组测试数据的相应结果。

样例 #1

样例输入 #1

1 3
thisisabookyouareaoh
4
is
a
ok
sab

样例输出 #1

7

提示

【数据范围】
对于 \(100\%\) 的数据,\(2 \le k \le 40\),\(1 \le s \le 6\)。

【样例解释】
划分方案为 this / isabookyoua / reaoh

【题目来源】

NOIP 2001 提高组第三题

代码如下

#include <bits/stdc++.h>
using namespace std;
int n;
int sum[205][205];
string word[10];
string s="";
bool f(int l,int r){ 
	string x=s.substr(l,r-l+1);
	for(int i=0;i<n;i++) if(x.find(word[i])==0){
		return true; 
	} 
	return false;
}
int main() {
    memset(sum,0,sizeof sum);
	int p,k;
	cin>>p>>k;
	s="";
	string t;
	for(int i=0;i<p;i++){
		cin>>t;
		s+=t;
	} 
	cin>>n;
	for(int i=0;i<n;i++){
		cin>>word[i];
	}
	int len=s.size();
	for(int i=len-1;i>=0;i--){
		for(int j=i;j>=0;j--){
			//j到i的单词数 
			sum[j][i]=sum[j+1][i]; 
			if(f(j,i))sum[j][i]++;	 
		}
	}
	 
	int dp[205][205];
	memset(dp,0,sizeof dp);
	for(int i=0;i<k;i++){
		if(i==0)dp[i][i+1]=sum[i][i+1];
		else 
		dp[i][i+1]=dp[i-1][i]+sum[i][i+1];
	}
	for(int i=0;i<len;i++) dp[i][1]=sum[0][i];
	for(int i=0;i<len;i++){
		for(int j=1;j<=k&&j<i+1;j++){
			for(int t=j-1;t<i;t++){
				//dp[i][j]=max(dp[i][j],dp[t][j-1]+sum[t+1][i])
				dp[i][j]=max(dp[i][j],dp[t][j-1]+sum[t+1][i]);
			}
		}
	} 
	cout<<dp[len-1][k];
    
    return 0; 
}


posted @ 2023-11-03 11:30  hey在干嘛  阅读(46)  评论(0)    收藏  举报