ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

1057 [NOIP2001]统计单词个数 划分区间 线性DP

2022-07-22 21:37:33  阅读:136  来源: 互联网

标签:NOIP2001 1057 int 字母 个数 单词 length dp DP


链接:https://ac.nowcoder.com/acm/problem/16696
来源:牛客网

题目描述

给出一个长度不超过200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。要求将此字母串分成k份( 1 < k ≤ 40 ),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含this和is,选用this之后就不能包含th)。 单词在给出的一个不超过6个单词的字典中。 要求输出最大的个数。

输入描述:

每组的第一行有2个正整数(p,k)
p表示字串的行数,k表示分为k个部分。
接下来的p行,每行均有20个字符。
再接下来有1个正整数s,表示字典中单词个数。(1 ≤ s ≤ 6 )
接下来的s行,每行均有1个单词。

输出描述:

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

输入

复制
1 3
thisisabookyouareaoh
4
is
a
ok
sab

输出

复制
7

分析

这题问的是给一场串字母分块,问每块所拥有的单词数之和最大是多少。

所以得先预处理出来每一块区间内的字符串数量是多少,

DP 考虑一个dp[i][j]表示前i个字母分成了j段时最大的单词数目,那么我们枚举一个位置p,

在这个位置将字符串分成两段,那么这个dp[i][j]=max(dp[p][j-1]+s[p+1][i]),

我们定义s[i][j]s[i][j]表示在文本串(即文章)的第i个位置到第j个位置,以每个位置开头,以j为结尾,总共有多少单词。

那么s数组可以用lenght(T) ^ 3×number(单词)的效率预处理,然后dp数组可以用length(T) ^ 2×k的效率直接搞出来。

DP的优化手段:如果单词数目比较多弄个Trie就可以把number的常数直接弄掉。同时s数组应该还可以用递推搞一搞,那么又可以把预处理的效率弄成length(T)

2
。然后在实际操作中dp数组还可以用单调队列优化一下,那么就可以把一个length(T)给弄掉。

 

PS:发现ms(f,0x3f)是负无穷

#include<bits/stdc++.h>
using namespace std;
const int N = 210;
int val[N*N],ch[N*N][26],f[N][60],s[N][N];
int NodeCnt = 0,n,m,len,k;//字母个数,行数,单词个数,字母长度,分块数量。
string in,T;
void insert(string in) {
    int u = 0;
    for(int i = 0;i<in.length();i++ ) {
        int c = in[i] - 'a';
        if(!ch[u][c]) ch[u][c] = ++ NodeCnt;
        u = ch[u][c];
    }
    val[u] = 1;
}

int query(int l,int r) {
    int sum = 0;
    for(int i = l;i<=r;i++) {
        int u = 0;
        for(int j = i;j<=r;j++) {
            int c = T[j] - 'a';
            if(!ch[u][c]) break;
            u = ch[u][c];
            if(val[u]) {sum ++ ;break;}
        }
    }
    return sum;
}

int main() {
    ios::sync_with_stdio(0);
    while(cin>>n>>k) {
        T = "";
        for(int i = 0;i<n;i++ ) {
            cin>>in;
            T = T + in;
        }
        len = T.length();
        cin>>m;
        for(int i = 0;i<m;i++ ){
            cin>>in;
            insert(in);
        }
        for(int i = 0;i<len;i++ ){
            for(int j = i;j<len;j++ ) {
                s[i][j] = query(i,j);
            }
        }
        memset(f,~0x3f,sizeof f);
        for(int i = 0;i<len;i++) {
            f[i][1] = s[0][i];
        }
        for(int i = 0;i<len;i++) {
            for(int j = 2;j<=k;j++) {
                for(int p = 0;p<i;p++) {
                    f[i][j] = max(f[i][j],f[p][j-1] + s[p+1][i]);
                }
            }
        }
        cout<<f[len - 1][k];
    }
    return 0;
}

 

标签:NOIP2001,1057,int,字母,个数,单词,length,dp,DP
来源: https://www.cnblogs.com/er007/p/16508003.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有