2/10 P1026 统计单词(跟昨天的P1018乘积最大差不多)

说是差不多啦,但还是不看题解不会做www

思路一样,只是乘积最大那道题里,分割点是m,这道题里段数是m,所以循环条件和初始化有些不一样

先看转移方程:
dp [ i ][ j ] = max ( dp [ i ] [ j ] , dp [ m ] [ j - 1 ] + have [ m + 1 ] [ i ] )

因为 m 代表的是段数,如果 m = i 的话,m+1 就会超过 i ,所以 m<=i-1
那不是还有 i 个字母全部都自成一段的情况会漏掉吗?
那就提前解决这种特殊情况
dp[i][i]=dp[i-1][i-1]+have[i][i]____i<=k!,最多分k段!

然后是怎么找每段里有多少个单词:
我们是用 string 的 find 来找的,返回的是第一个找到的引索,所以如果从前往后找的话,会一直返回第一个,找不到后面的,所以要从后往前找
然后是前后边界 l 和 r ,当 l 往左移动一次,那么当前状态的总数自然要加上(l+1,r),如果新区间内 存在一个单词的引索为 0,那么就 +1

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long int LL;
int p,k,word,dp[220][50],have[220][220],len;
string s,t,dic[8];

bool ck(int l,int r){
	string a;
	a=s.substr(l,r-l+1);
	for(int i=1;i<=word;i++){
		if(a.find(dic[i])==0) return true;
	}
	return false;
}

int main()
{
	cin>>p>>k;
	s+='0';
	for(int i=1;i<=p;i++)
	{
		cin>>t;
		s+=t;
	}
	cin>>word;
	for(int i=1;i<=word;i++)
	{
		cin>>dic[i];
	}
	len=s.length()-1;
	for(int i=len;i>=1;i--)
	{
		for(int j=i;j>=1;j--)
		{
			have[j][i]=have[j+1][i];
			if(ck(j,i))
			{
				have[j][i]++;
			}
		}
	}
	for(int i=1;i<=k;i++)
	{
		dp[i][i]=dp[i-1][i-1]+have[i][i];
	}
	for(int i=1;i<=len;i++)
	{
		dp[i][1]=have[1][i];
	}
	for(int i=2;i<=len;i++)
	{
		for(int j=1;j<=min(i-1,k);j++)
		{
			for(int m=j;m<i;m++)
			{
				dp[i][j]=max(dp[i][j],dp[m][j-1]+have[m+1][i]);
			}
		}
	}
	cout<<dp[len][k];
	return 0;
}

posted @   石磨豆浆  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示