1. 程式人生 > >統計單詞個數(NOIP 2001提高組)

統計單詞個數(NOIP 2001提高組)

sample 字符串 重疊 -s pre rom 長度 最大的 解析

題目描述 Description

給出一個長度不超過200的由小寫英文字母組成的字母串(約定;該字串以每行20個字母的方式輸入,且保證每行一定為20個)。要求將此字母串分成k份(1<k<=40),且每份中包含的單詞個數加起來總數最大(每份中包含的單詞可以部分重疊。當選用一個單詞之後,其第一個字母不能再用。例如字符串this中可包含this和is,選用this之後就不能包含th)(管理員註:這裏的不能再用指的是位置,不是字母本身。比如thisis可以算做包含2個is)。
單詞在給出的一個不超過6個單詞的字典中。
要求輸出最大的個數。

輸入描述 Input Description

第一行為一個正整數(0<n<=5)表示有n組測試數據
每組的第一行有二個正整數(p,k)
p表示字串的行數;
k表示分為k個部分。
接下來的p行,每行均有20個字符。
再接下來有一個正整數s,表示字典中單詞個數。(1<=s<=6)
接下來的s行,每行均有一個單詞。

輸出描述 Output Description

每行一個整數,分別對應每組測試數據的相應結果。

樣例輸入 Sample Input

1
1 3
thisisabookyouareaoh
4
is
a
ok
sab

樣例輸出 Sample Output

7

數據範圍及提示 Data Size & Hint

this/isabookyoua/reaoh


至今我遇到的最皮的動態規劃,要用兩次DP,而且還與字符串有關(絕望……),但是,還好有學長!

解析:

我們先要把每個單詞在整段字符串但凡存在,就把 str[ from ][ to ] 標記為1

然後進行第1次DP——推出任意一段存在的最多單詞數

接著,就和先前發的 山區建小學 的DP一模一樣,就是找 k 個分解點,只不過本題是 求出最多的數量

代碼^-^

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int str[201][201],f[201][201]; char ls[201]; int main() { int T; scanf("%d",&T); while(T--) { int p,k; scanf("%d%d",&p,&k); int l=20*p; for(int i=0;i<p;++i){ scanf("%s",ls+i*20); } int s; scanf("%d",&s); for(int i=1;i<=s;++i) { char lc[201]; scanf("%s",lc); int ll=strlen(lc); for(int j=0;j<l;++j) { int sf=1,t=j; for(int o=0;o<ll;++o,++t) if(ls[t]!=lc[o]) { sf=0; break; } if(sf) str[j+1][j+ll]=1; } } for(int j=2;j<=l;++j) for(int i=j-1;i;--i) if(str[i][j]) str[i][j]+=str[i+1][j]; else str[i][j]=str[i+1][j]+str[i][j-1]-str[i+1][j-1]; for(int i=1;i<=l;++i) f[i][1]=str[1][i]; for(int i=2;i<=l;++i) for(int j=2;j<=k && j<=i;++j) for(int q=j-1;q<i;++q) f[i][j]=max(f[i][j],f[q][j-1]+str[q+1][i]); printf("%d",f[l][k]); memset(str,0,sizeof(str)); memset(f,0,sizeof(f)); } return 0; }

統計單詞個數(NOIP 2001提高組)