RQNOJ 302 PID302 / [NOIP2001]統計單詞個數(區間dp)

畫船聽雨發表於2014-04-16

區間dp,狀態轉移公式是:dp[i][j] = max{dp[i][j], dp[i-1][k]+sum[k+1][j] };預處理出來所有的i到j有多少種情況。列舉每個區間。預處理有點麻煩。

題目描述

給出一個長度不超過200的由小寫英文字母組成的字母串(約定;該字串以每行20個字母的方式輸入,且保證每行一定為20個)。要求將此字母串分成k份(1<k<=40),且每份中包含的單詞個數加起來總數最大(每份中包含的單詞可以部分重疊。當選用一個單詞之後,其第一個字母不能再用。例如字串this中可包含this和is,選用this之後就不能包含th)。

單詞在給出的一個不超過6個單詞的字典中。

要求輸出最大的個數。

輸入格式

第一行有二個正整數(p,k)

p表示字串的行數;

k表示分為k個部分。

接下來的p行,每行均有20個字元。

再接下來有一個正整數s,表示字典中單詞個數。(1<=s<=6)

接下來的s行,每行均有一個單詞。

輸出格式

一個整數,結果。

#include <algorithm>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <iomanip>
#include <stdio.h>
#include <string>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <set>
#define eps 1e-8
#define M 1000100
#define LL __int64
//#define LL long long
#define INF 0x3f3f3f3f
#define PI 3.1415926535898

using namespace std;

const int maxn = 2010;

int dp[maxn][50];
char str[maxn];
char st[20][20];
char s[maxn];
int cnt[maxn][maxn];
int sum[maxn][maxn];

int main()
{
    int n, m;
    while(cin >>n>>m)
    {
        memset(dp, 0 , sizeof(dp));
        for(int i = 0; i < n; i++)
        {
            cin >>s;
            for(int j = i*20, k = 0; k < 20; k++, j++)
                str[j] = s[k];
        }
        int t;
        cin >>t;
        for(int i = 0; i < t; i++)
            cin >>st[i];
        int len = strlen(str);
        for(int i = 0; i < len; i++)
        {
            int mi = len;
            for(int j = 0; j < t; j++)
            {
                int kk = 0;
                if(str[i] == st[j][0])
                {
                    for(kk = 0; kk < strlen(st[j]) && (i+kk) < len; kk++)
                    {
                        if(str[i+kk] != st[j][kk])
                            break;
                    }
                    if(kk == strlen(st[j]))
                        mi = min(mi, i+kk-1);
                }
            }
            for(int j = mi; j < len; j++)
                cnt[i][j] = 1;
        }
        for(int i = 0; i < len; i++)
            sum[len-1][i] = cnt[len-1][i];
        for(int i = len-2; i >= 0; i--)
        {
            for(int j = i; j < len; j++)
            {
                if(cnt[i][j])
                    sum[i][j] = sum[i+1][j]+1;
                else
                    sum[i][j] = sum[i+1][j];
            }
        }
        for(int i = 0; i < len; i++)
            dp[1][i] = sum[0][i];
        for(int i = 2; i <= m; i++)
            for(int j = 0; j < len; j++)
                for(int k = i-2; k < j; k++)
                    dp[i][j] = max(dp[i][j], dp[i-1][k]+sum[k+1][j]);
        cout<<dp[m][len-1]<<endl;
    }
    return 0;
}


相關文章