zoukankan      html  css  js  c++  java
  • 【luogu P1026统计单词个数】 题解

    统计单词个数

    题目描述

    给出一个长度不超过200200的由小写英文字母组成的字母串(约定;该字串以每行20个字母的方式输入,且保证每行一定为20个)。

    要求将此字母串分成k份(1<=k40),且每份中包含的单词个数加起来总数最大(每份中包含的单词可以部分重叠。

    当选用一个单词之后,其第一个字母不能再用。例如字符串this中可包含thisis,选用this之后就不能包含th)。

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

    要求输出最大的个数。

    输入格式

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

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

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

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

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

    输出格式

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

    输入输出样例

    输入 #1
    1 3
    thisisabookyouareaoh
    4
    is
    a
    ok
    sab
    
    输出 #1
    7
    

    说明/提示

    this/isabookyoua/reaoh

    在做这道题之前,可以先了解以下几个的STL函数。

    1.  s.substr(x,y)  在s中取出下标从x开始长度为y的字符串(第一个字母下标为0)。

    2.  s.find(t)  在s中寻找字符串t,找到则返回0,找不到则返回一个极大值。

    3. s.length() 返回字符串s的长度。 

    此外,分析题意,可以明确的判定为是一道区间dp题。

    我们记

    sum[i][j]为在字符串中q区间[ i , j ]里出现的单词个数。

    dp[i][j]为处理完前i个字母,分成j个区间,能得到的单词个数。

    那么得到转移方程:

    dp[i][j] = max(dp[i][j] , dp[t-1][j-1] + sum[t][i]), t∈(j,i)

    因为划分为j-1个区间,最骚需要j-1个字母,所以t从j开始dp。

    最困难的转移方程解决后,我们在来想想怎么初始化。

    题目要求说一个字母只能是一个单词的开头。

    那么我们考虑倒序。

    首先,我们从右往左枚举区间右端点。

    然后从在右往左枚举区间左端点,先继承上一个左端点的sum,在判断当前的这个左端点是否能作为某个单词的开头。

    如果能就+1.

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    using namespace std;
    int dp[1000][100],sum[1000][1000];
    int p,k,m,len;
    string s="0",ch,a[1000];
    inline bool check(int l,int r){//判断是否有一个单词以l开头。
        string x=s.substr(l,r-l+1);
        for(int i=1;i<=m;i++)
            if(x.find(a[i])==0) return true;
        return false;
    }
    int main()
    {
        int i,j,t;
        scanf("%d%d",&p,&k);
        for(i=1;i<=p;i++){
            cin>>ch;
            s+=ch;
        }
        scanf("%d",&m);
        for(i=1;i<=m;i++) cin>>a[i];
        len=s.length()-1;
        for(i=len;i>=1;i--)
        for(j=i;j>=1;j--){
            sum[j][i]=sum[j+1][i];//继承前一个区间
            if(check(j,i)) 
            sum[j][i]++;
        }
        for(i=1;i<=len;i++)
            for(j=1;j<=k&&j<=i;j++)
                for(t=j;t<=i;t++)//dp核心
                    dp[i][j]=max(dp[i][j],dp[t-1][j-1]+sum[t][i]);
        printf("%d",dp[len][k]);
    }
  • 相关阅读:
    枚举显示中文问题
    各种计算机体系结构的特点与应用(SMP、MPP等)
    Redis应用
    如果是除去末尾特定字符或字符串:TrimEnd方法性能优于Remove方法
    N笔试题
    PropertyGrid中的枚举显示为中文
    【1.2.3】操作系统性能优化
    【T4实践(一)】模板生成代码入门
    构成计算机的各类部件的功能及其相互关系
    net中String是引用类型还是值类型
  • 原文地址:https://www.cnblogs.com/quitter/p/11720772.html
Copyright © 2011-2022 走看看