洛谷P1026统计单词个数题解--zhengjun

题目描述

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

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

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

要求输出最大的个数。

输入格式

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

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

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

输出格式

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

输入输出样例
输入 #1 复制
1 3
thisisabookyouareaoh
4
is
a
ok
sab
输出 #1 复制
7
说明/提示
【数据范围】

对于 100 % 100\% 100% 的数据, 2 ≤ k ≤ 40 2 \le k \le 40 2k40 1 ≤ s ≤ 6 1 \le s \le 6 1s6

【样例解释】

划分方案为 t h i s / i s a b o o k y o u a / r e a o h this / isabookyoua / reaoh this/isabookyoua/reaoh

思路

首先,这是一道有点难度的动态规划。
f i , j f_{i,j} fi,j 表示 从尾巴用了 i i i 个字符分了 j j j 段的最多有多少个单词。
则转移方程不难想到:
f i , j = m a x ( f i , j , f l , j − 1 + s u m l + 1 , i ) f_{i,j}=max(f_{i,j},f_{l,j-1}+sum_{l+1,i}) fi,j=max(fi,j,fl,j1+suml+1,i)
s u m sum sum 就是从 j j j i i i 的单词个数
然后 s u m sum sum 就可以在前面预处理暴力算出来

代码

#include<bits/stdc++.h>
using namespace std;
int p,n,m,k,f[210][50],sum[210][210];
string s,a[10];
bool check(int l,int r){
    string x=s.substr(l,r-l+1);//这个函数就是返回字符串s从第l个字符开始后面的r-l+1个字符所组成的字符串
    for(int i=1;i<=n;i++)
	     if(x.find(a[i])==0)//这个函数可以返回a[i]在x中最早出现的位置
		     return 1;
    return 0;
}
int main(){
    string ch;
    s+='0';
    cin>>p>>k;
    for(int i=1;i<=p;i++){
        cin>>ch;
        s+=ch;
    }
    cin>>n;
	m=s.length()-1;
    for(int i=1;i<=n;i++)
		cin>>a[i];
    for(int i=m;i>=1;i--)
    	for(int j=i;j>=1;j--){
    	    sum[j][i]=sum[j+1][i];
   	        if(check(j,i))
			    sum[j][i]++;
   		}
    f[0][0]=0;
    for(int i=1;i<=k;i++)
		f[i][i]=f[i-1][i-1]+sum[i][i];
    for(int i=1;i<=m;i++)
		f[i][1]=sum[1][i];
    for(int i=1;i<=m;i++)
    	for(int j=1;j<=k&&j<i;j++)
    		for(int k=j;k<i;k++)
    			f[i][j]=max(f[i][j],f[k][j-1]+sum[k+1][i]);
    printf("%d",f[m][k]);
    return 0;
}

谢谢–zhengjun

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A_zjzj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值