题目大意:
有一个单词串An,可以把单词串分成k份,
定义区间单词数如下:
已知有一个单词字典如:apple,hi.....
在串中的单词数:然后在串中统计有多少个单词,唯一注意的是,若串中某个字母作为单词首字母用了,那么这个串中的字母就不能作为下一个单词的首字母。
例如:thise
字典中有单词this 和 thise
那么这个串中只能有this或者thise,而不能两个单词都存在。
问:我们怎么对单词划分,可以使得每一份中的单词数相加后最多。
解题思路:
由于求最大值,而且是区间问题,考虑区间DP。另一种解题入手点是贪心,但是这里没办法证明贪心是有效的。
定义状态memo[n][k],表示长度为n的序列,划分k份的最大单词数。
我们可以得到状态转移如下:
for r = k-1:n
memo[n][k] = max( memo[r][k-1] + w[r+1][n])
其中w[i][j],表明区间[i,j]包含的单词数。
w[i][j]可以使用暴力求解。具体为枚举i,j的同时,在区间内走,同时枚举单词。
废话:
这种区间题,要想到区间DP。
同时,暴力解题的思路我们要为了降低复杂度,我们要考虑多次枚举。
#include <bits/stdc++.h>
using namespace std;
const int MAXN =210;
const int MAXK =50;
int memo[MAXN][MAXK];
int w[MAXN][MAXN];
int dfs(int n,int k){
if(k==1)return memo[n][k]=w[1][n];
if(n==k){
int sum=0;
for(int i=0;i<k;i++){
sum+=w[i][i];
}
return memo[n][k]=sum;
}
if(memo[n][k]!=-1)return memo[n][k];
int tmpans=-1;
for(int r=n-1;r>=k-1;r--){
tmpans=max(tmpans,dfs(r,k-1)+w[r+1][n]);
}
return memo[n][k]=tmpans;
}
int main(){
int p,k;cin>>p>>k;
string str("");
for(int i=0;i<p;i++){
string tmp;cin>>tmp;
str+=tmp;
}
int word;cin>>word;
map<int,vector<string>> mm;
for(int i=0;i<word;i++){
string wo;cin>>wo;
mm[wo[0]-'a'].push_back(wo);
}
int sz=str.size();
for(int i=0;i<sz;i++){
for(int j=i;j<sz;j++){
int sum=0;
for(int z=i;z<=j;z++){
int suc=0;
for(auto it:mm[str[z]-'a']){
int count=0;
while(count<(int)it.size()&&z+count<=j&& str[z+count]==it[count])count++;
if(count==(int)it.size()){
suc=1;
break;
}
}
if(suc)sum++;
}
w[i+1][j+1]=sum;
}
}
memset(memo,-1,sizeof(memo));
int ans=dfs(sz,k);
cout<<ans<<endl;
return 0;
}