P1026 统计单词个数 [dp]

P1026 统计单词个数

这道题看上去就是要用dp的样子。裸裸的dp题无误。

首先要把分开的字符串合成那个长度小于等于\(200\)的总字符串。

然后做个预处理,预处理出任意区间内的单词个数,设为\(sum[i][j]\)

有一个神奇的地方:

当选用一个单词之后,其第一个字母不能再用。

题解里面有这么一种解决方式:

倒序枚举\(j\)\(i\)。初始化\(sum[i][j] = sum[i + 1][j]\)。如果子串中从一开始就存在单词,加1。

其实不怎么知道原理这种做法还刚好满足了上面的限制。

然后套上一种区间dp的思路,3重枚举更新dp。

因为若要分\(k\)段,则至少也要已经遍历过\(k\)个字符串,所以至少要从\(k\)开始。

代码:

/*************************************************************************
 @Author: Garen
 @Created Time : Tue 29 Jan 2019 09:56:30 PM CST
 @File Name: P1026.cpp
 @Description:
 ************************************************************************/
#include<bits/stdc++.h>
using std::cin;
using std::cout;
using std::endl;
using std::string;
#define ll long long
const int maxn = 205;
string str;
string word[8];
int dp[maxn][maxn];
int pd[maxn];
int p, m, s, n;
int sum[maxn][maxn];
int check(int l, int r) {
    l--; r--;
    string ch = str.substr(l, r - l + 1);
    for(int i = 1; i <= s; i++) {
        if(ch.find(word[i]) == 0) return 1;
    }
    return 0;
}
int main() {
    cin >> p >> m;
    string temp;
    while(p--) {
        cin >> temp;
        str = str + temp;
        n += temp.length();
    }
    cin >> s;
    for(int i = 1; i <= s; i++) cin >> word[i];
    for(int j = n; j >= 1; j--) {
        for(int i = j; i >= 1; i--) {
            sum[i][j] = sum[i + 1][j] + check(i, j);
        }
    }
    for(int i = 1; i <= m; i++) dp[i][i] = dp[i - 1][i - 1] + sum[i][i];
    for(int i = 1; i <= n; i++) dp[i][1] = sum[1][i];
    for(int i = 1; i <= n; i++) {
        for(int j = 2; j <= m && j < i; j++) {
            for(int k = j; k < i; k++) {
                dp[i][j] = std::max(dp[i][j], dp[k][j - 1] + sum[k + 1][i]);
            }
        }
    }
    cout << dp[n][m] << endl;
    return 0;
}
posted @ 2019-01-30 00:28  Garen-Wang  阅读(272)  评论(0编辑  收藏  举报