• luogu P1026 统计单词个数


    题目描述

    给出一个长度不超过 200 的由小写英文字母组成的字母串(该字串以每行 20 个字母的方式输入,且保证每行一定为 20 个)。要求将此字母串分成 k 份,且每份中包含的单词个数加起来总数最大。

    每份中包含的单词可以部分重叠。当选用一个单词之后,其第一个字母不能再用。例如字符串 this 中可包含 this 和 is,选用 this 之后就不能包含 th。

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

    要求输出最大的个数。

    输入格式

    每组的第一行有两个正整数 p,k . p 表示字串的行数,k 表示分为 k 个部分。

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

    再接下来有一个正整数 s 表示字典中单词个数。 接下来的 s 行,每行均有一个单词。

    输出格式

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

    输入输出样例

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


    【样例解释】 划分方案为 this / isabookyoua / reaoh


    • 此题第一个难点是意识到如果有两个字母同时符合要求, 最短的那个会更优(贪心).

    • 第二个难点是字符串的预处理. End[x]表示从x开始的最短的那个单词的最后一个字母的位置.如abcde里找ab单词, 那么End[1]=2.

    • 此题最难的部分是DP方程如何转移.

    • 我们假设DP[i][q]表示已经到了第i个字符, 如果此时在第i位字符后面砍第q刀,会得到的单词出现次数的总和.

    • 首先想到DP[i][q]从DP[j][q-1]来转移, 同时查找j+1到i位的单词个数. 但是 O(n3*k2), 会超.

    • 那么只好优化这个转化过程. 我们可以发现j+2到i位的单词个数可以算到j+1到i位的单词个数里面. 所以j采取倒序循环, 用一个t累计,从i一直到q

    (为啥是q, 你想啊, 你想砍第q刀是不是至少要从第q个字母开始枚举)

    代码如下

    #include<bits/stdc++.h>
    #define MN 1005
    #define Inf 0x3f3f3f3f
    #define ll long long
    using namespace std;
    int p,k,s,len,End[MN];
    ll dp[MN][45];
    string str;
    char Sen[MN];
    char Wor[11][MN];
    bool Find(int x,int y){
        string Cmp="";
        for(int i=x;i<=y;i++)Cmp+=Sen[i];
        for(int i=1;i<=s;i++)
    	if(string(Cmp)==string(Wor[i]+1))
        {
        return 1;
        }
        return 0;
    }
    void pre(int i){
         for(int j=i;j<=len;j++){
            if(Find(i,j)){
                End[i]=j;
                return;
            } 
         }
    }
    void Inp(){
    	memset(End,0x3f,sizeof(End));
    	cin>>p>>k;
    	len=p*20;
    	for(int i=1;i<=len;i++){
    		cin>>Sen[i];
    	}
    	cin>>s;
    	for(int i=1;i<=s;i++)
        	scanf("%s",Wor[i]+1);
        	
    }
    int main(){
    	
        Inp();
    	for(int i=1;i<=len;i++)
        	pre(i);
    	for(int i=1;i<=len;i++){
    	      for(int q=1;q<=k;q++){
                        int t=0;
    		       for(int j=i;j>=q;j--){
                     	if(End[j]<=i)
                               t++;
    	                 dp[i][q]=max(dp[i][q],dp[j-1][q-1]+t);
                     	
    		     }
                   }
    		
    	}
    	printf("%ld",dp[len][k]);
    	return 0;
    } 
    
  • 相关阅读:
    [nRF51822] 1、一个简单的nRF51822驱动的天马4线SPI-1.77寸LCD彩屏DEMO
    [安卓] 18、一个简单的例子做自定义动画按钮和自定义Actionbar
    [自己动手玩黑科技] 1、小黑科技——如何将普通的家电改造成可以与手机App联动的“智能硬件”
    [安卓] 17、一个简单的例子学安卓侧滑设计——用开源slidingmenu
    [安卓] 16、ListView和GridView结合显示单元实现自定义列表显示效果
    mysql常用处理时间的相关函数
    Mysql中HAVING的相关使用方法
    mysql中常见正则表达式的应用
    Linux系统模拟发送HTTP的get和post请求
    mysql删除字符串的前后的空格
  • 原文地址:https://www.cnblogs.com/GUOGaby/p/13887463.html
Copyright © 2020-2023  润新知