P1026 统计单词个数 区间dp

  

题目描述

给出一个长度不超过200200的由小写英文字母组成的字母串(约定;该字串以每行2020个字母的方式输入,且保证每行一定为2020个)。要求将此字母串分成kk份(1<k \le 401<k40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串thisthis中可包含thisthis和isis,选用thisthis之后就不能包含thth)。

单词在给出的一个不超过66个单词的字典中。

要求输出最大的个数。

输入输出格式

输入格式:

每组的第一行有22个正整数(p,kp,k)

pp表示字串的行数,kk表示分为kk个部分。

接下来的pp行,每行均有2020个字符。

再接下来有11个正整数ss,表示字典中单词个数。(1 \le s \le 61s6)

接下来的ss行,每行均有11个单词。

输出格式:

11个整数,分别对应每组测试数据的相应结果。

输入输出样例

输入样例#1:  复制
1 3
thisisabookyouareaoh
4
is
a
ok
sab
输出样例#1:  复制
7

说明

this/isabookyoua/reaoh

一共有两个dp

第一个dp为预处理

必须要从后往前转移  这样遇到重复的也不会影响结果   如题意所得  每次判断具有后效性   所以当遇到这种情况的时候一定要从后往前dp  之前有一道安排工作的dp也是一样!!!!

注意 预处理的细节

第二个dp为区间dp

划分为k个区域只要加上k-1个隔板即可

然后就是注意 区间dp各种小细节!!!!

我做的时候有个疑问  为什么分隔点是s后面  而不能是当前处理区间末尾的前面一格分隔  

想一想就知道是错的!!!。。。

#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);i--)
#define RI(n) scanf("%d",&(n))
#define RII(n,m) scanf("%d%d",&n,&m)
#define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
#define RS(s) scanf("%s",s);
#define LL long long
#define REP(i,N)  for(int i=0;i<(N);i++)
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
#define inf 2147483647
#define N 200
string s;
int k,q,n;
string table[10];
int word[210][210];
int dp[210][50];
int len;
bool check(int i,int j)
{
   /* string temp=s.substr(i,j-i+1);
    rep(i,1,q)if(temp.find(table[i])==0)return true;
    */
    rep(k,1,q)
    {
        if(table[k].size()>j-i+1)continue;
        if(s.substr(i,table[k].size())==table[k])return true;
    }
    return false;
}
void init()
{
    repp(j,len,1)
    repp(i,j,1)
    {
        word[i][j]=word[i+1][j];
        if(check(i,j))word[i][j]++;
    }
}
int main()
{
    RII(n,k);
    rep(i,1,n)
    {
        string temp;
        cin>>temp;
        s+=temp;
    }
    len=s.size();
    s='*'+s;//方便处理
    RI(q);
    rep(i,1,q)
    cin>>table[i];
    init();
    rep(i,1,len)
    dp[i][0]=word[1][i];

    rep(i,1,k-1)//加入k-1个 分隔   最后就会分成k块
    rep(j,i+1,len)
    rep(s,i,j-1)//枚举断点s
    dp[j][i]=max(dp[j][i],dp[s][i-1]+word[s+1][j]);//我不知道为什么改成word[s][j-1]不行 (否则 第三层循环没有任何意义  答案永远不会再更新了!!!)

    cout<<dp[len][k-1];
}
View Code

猜你喜欢

转载自www.cnblogs.com/bxd123/p/10687311.html