题目
思路
本题很明显的是区间DP,但是多了个划分次数的量k,当k还小于kk(题目给的k)的时候就还得继续划分。没关系,本题常数小,状态上还可以加个k。
1.状态定义:d(i,j,k),区间[i,j]内已经划分了次数k时,最大的单词数。
2.状态转移:
(1).当k = kk时,直接计算区间[i,j]的单词数即可。
d[i][j][k]=c[i][j]
d
[
i
]
[
j
]
[
k
]
=
c
[
i
]
[
j
]
(2).当k < kk时,枚举l∈[i,j),就得到两个区间[i,l],[l+1,j],这两个区间选一个作为成品区间让它k=kk,另外一个继续让它再划分即可。
d[i][j][k]=max{dp(i,l,kk)+dp(l+1,j,k+1),dp(i,l,k+1)+dp(l+1,j,kk)}
d
[
i
]
[
j
]
[
k
]
=
m
a
x
{
d
p
(
i
,
l
,
k
k
)
+
d
p
(
l
+
1
,
j
,
k
+
1
)
,
d
p
(
i
,
l
,
k
+
1
)
+
d
p
(
l
+
1
,
j
,
k
k
)
}
还有个问题是本题的预处理,也就是先算出cc[i][j],区间[i,j]的单词数。
我用了个递归解决,具体看代码即可。
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <set>
#include <iostream>
#define _for(i,a,b) for(int i = (a); i<(b); i++)
#define _rep(i,a,b) for(int i = (a); i<=(b); i++)
using namespace std;
const int INF = 10000;
const int maxn = 200+10;
const int maxz = 6 + 4;
const int maxk = 40 + 4;
int n, kk, p, dicnum, cc[maxn][maxn], d[maxn][maxn][maxk];
// cc[i][j]:[i,j]区间含有单词数,d[i][j][k]:[i,j]区间,已经划分了k次,的最大单词数
string s;
set<string> dic; // 常数很小,用set偷懒
int getcc(int i, int j) {
if (i == j) {
if (dic.count(s.substr(i, 0))) { cc[i][j] = 1; return 1; }
else { cc[i][j] = 0; return 0; }
}
bool have = false;
for (set<string>::iterator iter = dic.begin(); iter != dic.end(); iter++) {
if (s.substr(i).find(*iter) == 0 && (*iter).length() <= j-i+1) have = true;
}
int c = getcc(i + 1, j);
if (have) { cc[i][j] = c+1; return c+1; }
else { cc[i][j] = c; return c; }
}
int dp(int i, int j, int k) {
if (i > j) return -INF;
int &ans = d[i][j][k];
if (ans != -1) return ans;
ans = -INF;
if (k == kk)
ans = max(ans, cc[i][j]);
else {
_rep(l, i, j - 1) {
ans = max(ans, dp(i, l, kk) + dp(l + 1, j, k+1));
ans = max(ans, dp(i, l, k + 1) + dp(l + 1, j, kk));
}
}
return ans;
}
int main() {
// 输入
cin >> p >>kk;
string temp;
_for(i, 0, p) {
cin >> temp;
s += temp;
}
n = s.length();
cin >> dicnum;
_for(i, 0, dicnum) {
cin >> temp;
dic.insert(temp);
}
for (int j = n - 1; j > 0; j--)
getcc(0, j);
memset(d, -1, sizeof(d));
printf("%d\n", dp(0, n - 1, 1));
return 0;
}