【黄题 dp】P1026 [NOIP2001 提高组] 统计单词个数

发布时间 2023-03-28 20:25:45作者: 从零开始的acm

https://www.luogu.com.cn/problem/P1026

这题的idea首先是直接暴力枚举k,发现会t,遂想到dp

\(dp[i][k]\) 表示 前 \(i\) 个数形成了 \(k\) 段数字的最大答案

注意一个比较坑的点是可能同一个位置会有多个单词开始,但是只计数一个

eg:

1 2
then
2
the 
then

答案应该是 1

贴code(写的比较丑):

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1e5 + 10;
string str, s;
int p, k, n, x;
vector<string> v;
int dp[202][44];
int pre[202][202];

inline bool check(int l, int r) {
    string tem = s.substr(l, r - l + 1);
    for(auto x : v) {
        if(r - l + 1 >= x.size()) {
            if(tem.find(x) == 0) return 1;
        } 
    }
    return 0;
}

void init() {  // 预处理pre[l, r]
    for(int r = n; r >= 1; r--) {    // r 也可以从前往后
        for(int l = r; l >= 1; l--) {
            pre[l][r] = pre[l + 1][r];
            if(check(l, r)) pre[l][r]++; 
        }
    }
}

int main() {
    cin >> x >> k;
    while(x--) {
        cin >> str;
        s += str;
    }
    s = " " + s;
    n = s.size() - 1;
    if(k > n - 1) {
        puts("0");
        return 0;
    }
    cin >> p;
    for(int i = 1; i <= p; i++) {
        cin >> str;
        v.push_back(str);
    }

    init();

    for(int K = 1; K <= k; K++) {  // K <= k
        for(int i = 1; i <= n; i++) {  //  i < n
            for(int j = K - 1; j < i; j++) {
                dp[i][K] = max(dp[i][K], dp[j][K - 1] + pre[j + 1][i]);
            }
            // cout << "i: " << i << " k: " << K << "dp[i][K]: " << dp[i][K] << endl;
        }
    }
    cout << dp[n][k] << endl;
    return 0;
}