洛谷 P1026 统计单词个数 区间DP

题目描述

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

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

要求输出最大的个数。

输入输出格式

输入格式:

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

p表示字串的行数;

k表示分为k个部分。

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

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

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

输出格式:

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

输入输出样例

输入样例#1:

1 3
thisisabookyouareaoh
4
is
a
ok
sab

输出样例#1:

7

方法挺直接的,先求出每一段字符串包含了多少单词,再求出将整个字符串分割成 m 段最多可以获得多少单词。

dp[i][j]  表示前 i 个字符组成的串,分割成 j 段,最多能获得多少单词。

dp[i][j] = max(dp[k][j-1] + wordNum[k+1][length])   (j-1 <= k <= length-1)

代码:

#include <iostream>
#include <cstring>
using namespace std;

const int MAX = 205;
const int INF = 0x3fffffff;

int wordNum[MAX][MAX];        //i 到 j 这一段包括了多少个单词
int dp[MAX][MAX];        //剩下的 i 串,分成 j 段最多包含多少单词
string s;
string words[10];
int l, m, n;

int dfs(int i, int j);        //枚举 

int main(){
//    freopen("input.txt", "r", stdin);
    cin >> l >> m;
    s = "";
    while(l--){
        string t;
        cin >> t;
        s += t;
    }

    cin >> n;
    for(int i=1; i<=n; i++){
        cin >> words[i];
    }

    //求出 dp 数组
    memset(wordNum, 0, sizeof(wordNum));
    for(int len = 1; len <=s.length(); len++){
        for(int i=0; i+len-1<s.length(); i++){
            int j = i + len - 1;
            bool hasWord = false;
            for(int x=1; x<=n; x++){        //从最左边的字符开始能不能构成一个单词
                string t = words[x];
                int p = i, q = 0;
                while(p <= j && q < words[x].length()){
                    if(s[p] != words[x][q])
                        break;
                    p++;  q++;
                }
                if(q >= words[x].length()){
                    hasWord = true;
                    break;
                }
            }
            wordNum[i][j] = wordNum[i+1][j] + hasWord;    //能够成就加一
        }
    }

    memset(dp, 0, sizeof(dp));
    for(int i=0; i<s.length(); i++){
        dp[i][1] = wordNum[0][i];
    }
    for(int j=2; j<=m; j++){                    //分割成 j 段
        for(int i=0; i<s.length(); i++){        //有 i 个字符
            for(int k=j-2; k<i; k++){                //分割点
                dp[i][j] = max(dp[i][j], dp[k][j-1] + wordNum[k+1][i]);
            }
        }
    }

    cout << dp[s.length()-1][m];

    return 0;
}
时间: 2024-12-18 14:36:58

洛谷 P1026 统计单词个数 区间DP的相关文章

[NOIP2001] 提高组 洛谷P1026 统计单词个数

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

P1026 统计单词个数 【dp】

题目描述 给出一个长度不超过 200200 的由小写英文字母组成的字母串(该字串以每行 2020 个字母的方式输入,且保证每行一定为 2020 个).要求将此字母串分成 kk 份,且每份中包含的单词个数加起来总数最大. 每份中包含的单词可以部分重叠.当选用一个单词之后,其第一个字母不能再用.例如字符串 this 中可包含 this 和 is,选用 this 之后就不能包含 th. 单词在给出的一个不超过 66 个单词的字典中. 要求输出最大的个数. 输入格式 每组的第一行有两个正整数 p,kp,

luogu P1026 统计单词个数 序列DP

dp[i][k]表示,在i及i左侧,分成k块,的最大单词数目. w[i][j]表示,在[i,j],内部多少个单词在此区间开始和结束. 转移方程为dp[i][k] = max(dp[j][k - 1] + w[j + 1][i]) 通过考虑每个单词的结束而非开始,而避开后后效性问题. 如果某个单词是另一个单词的前缀,则另一个单词无需考虑. 字符串处理的有问题,调了挺久的.... 1 #include <cstdio> 2 #include <cstring> 3 #include &

P1026 统计单词个数 [dp]

P1026 统计单词个数 这道题看上去就是要用dp的样子.裸裸的dp题无误. 首先要把分开的字符串合成那个长度小于等于\(200\)的总字符串. 然后做个预处理,预处理出任意区间内的单词个数,设为\(sum[i][j]\). 有一个神奇的地方: 当选用一个单词之后,其第一个字母不能再用. 题解里面有这么一种解决方式: 倒序枚举\(j\)和\(i\).初始化\(sum[i][j] = sum[i + 1][j]\).如果子串中从一开始就存在单词,加1. 其实不怎么知道原理这种做法还刚好满足了上面的

luogu P1026 统计单词个数

题目链接 luogu P1026 统计单词个数 题解 贪心的预处理母本串从i到j的最大单词数 然后dp[i][j] 表示从前i个切了k次最优解 转移显然 代码 #include<cstdio> #include<algorithm> #include<cstring> const int maxn = 507; char a[maxn]; char s[maxn],t[maxn]; int dp[maxn][55]; int n,k,q; int num[maxn][m

P1026 统计单词个数——substr

P1026 统计单词个数 string 基本操作: substr(x,y) x是起始位置,y是长度: 返回的是这一段字符串: 先预处理sum[i][j],表示以i开头,最多的单词数: 从后往前寻找,保证开头没有被用过: sum[i][j]=sum[i+1][j]; 再找是否有新单词出现: s.find()==0说明找到单词以开头开始: 然后dp,f[i][j]表示以i结尾分j段的最大单词数: #include<cstdio> #include<string> #include<

P1026 统计单词个数

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

洛谷P1063 能量项链(区间DP)(环形DP)

To 洛谷.1063 能量项链 题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定等于后一颗珠子的头标记.因为只有这样,通过吸盘(吸盘是Mars人吸收能量的一种器官)的作用,这两颗珠子才能聚合成一颗珠子,同时释放出可以被吸盘吸收的能量.如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为m*r*n(M

洛谷 P1308 统计单词数【字符串+模拟】

P1308 统计单词数 题目描述 一般的文本编辑器都有查找单词的功能,该功能可以快速定位特定单词在文章中的位置,有的还能统计出特定单词在文章中出现的次数. 现在,请你编程实现这一功能,具体要求是:给定一个单词,请你输出它在给定的文章中出现的次数和第一次出现的位置.注意:匹配单词时,不区分大小写,但要求完全匹配,即给定单词必须与文章 中的某一独立单词在不区分大小写的情况下完全相同(参见样例1 ),如果给定单词仅是文章中某一单词的一部分则不算匹配(参见样例2 ). 输入输出格式 输入格式: 输入文件