中文题
想法:
其实我觉得这题的细节挺多的。
首先注意题目中的“每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串 this
中可包含 this
和 is
,选用 this
之后就不能包含 th
。”
这句话其实就要求我们需要倒序去更新而不能正序更新(自行思考),这样处理出各个区间之间单词个数
然后开始dp
f[i][k] 代表从1~i 分成 k 段的最大单词数
然后我们枚举断点去更新状态就好了 f[i][k] = max(f[j][k-1]+s[j+1][i],f[i][k])
#include <algorithm> #include <string> #include <string.h> #include <vector> #include <map> #include <stack> #include <set> #include <queue> #include <math.h> #include <cstdio> #include <iomanip> #include <time.h> #include <bitset> #include <cmath> #include <sstream> #include <iostream> #include <cstring> #define LL long long #define ls nod<<1 #define rs (nod<<1)+1 #define pii pair<int,int> #define mp make_pair #define pb push_back #define INF 0x3f3f3f3f const double eps = 1e-10; const int maxn = 200 + 10; const LL mod = 1e9 + 7; int sgn(double a){return a < -eps ? -1 : a < eps ? 0 : 1;} using namespace std; int f[maxn][maxn]; int sum[maxn][maxn]; string w[maxn],str; int n,k,p; bool check(int l,int r) { string x = str.substr(l,r-l+1); for (int i = 1;i <= n;i++) { if (x.find(w[i]) == 0) return true; } return false; } int main() { ios::sync_with_stdio(false); cin >> p >> k; str += "0"; for (int i = 1;i <= p;i++) { string s; cin >> s; str += s; } cin >> n; for (int i = 1;i <= n;i++) cin >> w[i]; int len = str.length()-1; for (int j = len;j >= 1;j--) { for (int i = j;i >= 1;i--) { sum[i][j] = sum[i+1][j]; if (check(i,j)) sum[i][j]++; } } f[0][0] = 0; for (int i = 1;i <= k;i++) f[i][i] = f[i-1][i-1] + sum[i][i]; for (int i = 1;i <= len;i++) f[i][1] = sum[1][i]; for (int i = 1;i <= len;i++) { for (int j = 1;j <= k && j < i;j++) { for (int l = j-1;l < i;l++) f[i][j] = max(f[i][j],f[l][j-1]+sum[l+1][i]); } } cout << f[len][k] << endl; return 0; }