• P1026 统计单词个数


    题目描述

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

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

    要求输出最大的个数。

    输入输出格式

    输入格式:

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

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

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

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

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

    输出格式:

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

    输入输出样例

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

    说明

    this/isabookyoua/reaoh

    Solution:

      字符串dp,套路就是定义状态$f[i][j]$表示到了母串$i$位置分成$j$块包含的单词最大个数。

      对于本题,如果我们知道$s[i][j]$(表示母串$i$到$j$之间的单词个数),则很容易将其转化为区间dp,不难得到状态转移方程:$f[i][j]=max(f[i][j],f[p][j-1]+s[p+1][i]),;pin [1,i)$。

      那么本题解决关键成了如何预处理$s[i][j]$,我的方法是字符串hash+暴力枚举,对母串和各匹配串均hash一下,然后直接枚举区间和断点,判断hash值是否相等就好了,然后注意细节:1、求hash值时可能爆int  2、每个位置只能做为一个匹配串的开头,匹配到了就直接break掉。

    代码:

    #include<bits/stdc++.h>
    #define il inline
    #define ll long long
    #define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
    #define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
    using namespace std;
    const int mod=998244353,P=131;
    int op[205],ha[205],l[7],p[7];
    int n,m,k,len,f[205][45],g[205][205];
    char s[205],t[205];
    bool vis[205];
    
    il void init(){
        cin>>m>>k;
        while(m--) For(i,1,20) cin>>s[++len];
        op[0]=1;
        For(i,1,len) op[i]=1ll*op[i-1]*P%mod,ha[i]=(1ll*ha[i-1]*P%mod+s[i]-'a')%mod;
        cin>>n;
        For(i,1,n) {
            cin>>t+1,l[i]=strlen(t+1);
            For(j,1,l[i]) p[i]=(1ll*p[i]*P+t[j]-'a')%mod;
        }
        For(i,1,len) For(j,i,len) For(k,i,j) For(o,1,n)
            if(k+l[o]-1<=j&&(ha[k+l[o]-1]-1ll*ha[k-1]*op[l[o]]%mod+mod)%mod==p[o]){g[i][j]++;break;}
    }
    
    int main(){
        ios::sync_with_stdio(0);
        init();
        For(o,1,k) For(i,1,len) For(j,o-1,i-1) f[i][o]=max(f[i][o],f[j][o-1]+g[j+1][i]);
        cout<<f[len][k];
        return 0;
    }
  • 相关阅读:
    又到泰山了
    有趣的数字
    关于Servlet/JSP里"/"的用法
    [WS]一个简单的WSDL文档(下)
    30天敏捷结果(28):撰写你的个人使命
    推荐:敏捷个人应该订阅的博客
    30天敏捷结果(27):做些有重要意义的事
    30天敏捷结果(29):找到适合你发展的环境
    COM+的配置:痛并快乐着
    30天敏捷结果(22):设计你的一天
  • 原文地址:https://www.cnblogs.com/five20/p/9427021.html
Copyright © 2020-2023  润新知