1. 程式人生 > >P1026 統計單詞個數 [dp]

P1026 統計單詞個數 [dp]

sum line bstr sin rip 個數 第一個 math length

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;
}

P1026 統計單詞個數 [dp]