统计单词个数 洛谷p1026

题目描述

给出一个长度不超过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

说明

this/isabookyoua/reaoh







因为不太会处理字符串,但看到判断字符相等,哈希有大用处了。

分别把每一个子串哈希一遍和目标串匹配,匹配完成将这一段加1;

预处理出来一个map[i][j]表示在从ij的区间里有合法的子串的个数.

那转移可以有以下,j为分的次数,i为当前分到第i个位置

··· dp[i][j]=max(dp[i][j],dp[1~i-1][j-1])

特殊的当j=1dp[i][1]=map[0][i]

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define f(i,l,r) for(i=(l);i<=(r);i++)
#define ff(i,r,l) for(i=(r);i>=(l);i--)
using namespace std;
const int Base=233,MOD=10000009;
char a[300],b[10][100];
int n,k,m,l[10],c[10],w[300][300];
int dp[300][300];
inline int ha(char b[],int len)
{
	int i;
	int val=0;
	f(i,1,len){
		val=(val*Base+b[i-1])%MOD;
	}
	return val;
}
inline int pd(int x,int y)
{
	int i;
	char tmp[15];
	f(i,1,m){
		if(y-x+1<l[i]) continue;
		strncpy(tmp,a+x,l[i]);
		if(ha(tmp,l[i])==c[i]) return 1;
	}
	return 0;
}
int main()
{
	ios::sync_with_stdio(false);
	int i,j,len,t;
	cin>>n>>k;
	f(i,1,n){
		cin>>a+(i*20-20);
	}
	len=strlen(a);
	cin>>m;
	f(i,1,m){
		cin>>b[i];
		l[i]=strlen(b[i]);
		c[i]=ha(b[i],l[i]);
	}
	ff(j,len-1,0){
		ff(i,j,0){
			w[i][j]+=w[i+1][j];
	//		if(i==5&&j==7) cout<<pd(i,j)<<"GG";
			if(pd(i,j)) w[i][j]++;
		}
	}
	f(i,0,len-1){
		f(j,i,len-1){
	//		cout<<i+1<<' '<<j+1<<' '<<w[i][j]<<endl;
		}
	}
	f(i,0,len-1){
		f(j,1,k){
			if(j==1) dp[i][j]=w[0][i];
			else{
				f(t,j-1,i-1){
			//		if(dp[t][j-1])
					dp[i][j]=max(dp[i][j],dp[t][j-1]+w[t+1][i]);
				}
			}
		}
	}
	cout<<dp[len-1][k]<<endl;
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值