luogu 1026 统计单词个数

此题 字符串匹配+dp

确实我的kmp,哈希需要练一练了,忘干净可咋办

补救用下string,十分方便

e.g:

1.询问a[i]是否是x子串,可以截取并判断前缀

   x为截取串 x.find(a[i])==0判断前缀即可

2.s+='0',其后利用+=便可挪移下标

 

dp方程 f[i][j]表示串到i位分了j个块的最大单词数

需要枚举l更新答案,并非直接用i更新

dp[i][j]=max(dp[i][j],dp[l][j-1]+sum[l+1][j])

sum[i][j]代表串由i位到j位的子串匹配的单词数,需要预处理

#include<bits/stdc++.h>

using namespace std;

int p,k,n,m;
string s,ch,a[10];
int f[205][50],sum[205][205];


//查询以i为起点,j为重点的串是否包含a[i],判断前缀 
bool check(int i,int j){
    string x=s.substr(i,j-i+1);
    for(int i=1;i<=n;i++)
       if(x.find(a[i])==0) return 1;
    return 0; 
}

void init(){
    s+='0';//补0挪移下标 
    cin>>p>>k;
    for(int i=1;i<=p;i++) cin>>ch,s+=ch;
    m=s.length()-1;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    
    //sum[i][j] 代表 由i到j 匹配的单词数 
    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];
}

int main(){
    ios::sync_with_stdio(false);
        
    init();
    
    for(int i=1;i<=m;i++)
    for(int j=1;j<=k&&j<i;j++)
    for(int l=j;l<i;l++)
       f[i][j]=max(f[i][j],f[l][j-1]+sum[l+1][i]);
    
    cout<<f[m][k]<<"\n";
    
    return 0;
}

 

posted @ 2018-08-25 13:23  ASDIC减除  阅读(133)  评论(0编辑  收藏  举报