NOIP 统计单词个数(区间DP)

满分做法:

(dp[i][j])表示到(i)位置分为(j)段的最大值,区间dp通常枚举断点,所以预处理(sum[i][j])表示区间([i,j])的单词数。

本题还用了string类型的小技巧,推荐做一下。

#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstdio>
using namespace std;
int p,k;
string s;
int dp[210][55];//dp[i][j]表示到i分为j段的最单词数 
int sum[210][210];
int n;
string a[8];
bool check(int l,int r)//寻找以l开头的字符串
{
 string x=s.substr(l,r-l+1);//裁剪
 for(int i=1;i<=n;i++)
 if(x.find(a[i])==0) return 1;//直接找字符串,返回开头位置
 return 0;
}
int main()
{
 scanf("%d%d",&p,&k);
 s+='$';//下表从1开始 
 for(int i=1;i<=p;i++)
 {
  string x;
  cin>>x;
  s+=x;	
 }
 scanf("%d",&n);
 for(int i=1;i<=n;i++)
 cin>>a[i];
 for(int i=1;i<=p*20;i++)//枚举结尾 
 {
   for(int j=i;j>=1;j--)//倒叙处理转移 
   {
   	 sum[j][i]=sum[j+1][i];
   	 if(check(j,i))
   	 sum[j][i]++;
   }
 }
 for(int j=1;j<=k;j++)
 {
  for(int i=1;i<=p*20;i++)
  {
   for(int q=j-1;q<i;q++)//枚举断点 
   {
     dp[i][j]=max(dp[i][j],dp[q][j-1]+sum[q+1][i]);
   } 
  }
 }
 printf("%d
",dp[p*20][k]);
 return 0;	
}
原文地址:https://www.cnblogs.com/lihan123/p/11669455.html