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;
}

浙公网安备 33010602011771号