动态规划、字符串

设计 $dp_{i,j}$ 为将前 $i$ 个字符分成 $j$ 串时每个串包含的单词数量之和。

如果一个位置能匹配多个单词,无论匹配哪一个单词都只会消耗第一个字母,所以单词全部等效。预处理所有子串包含的单词数量即可。

使用 $n$ 表示字符串长度,$m$ 表示单词数量,$k$ 表示分割得到子串的数量,时间复杂度 $O(n^3m+n^2k)$。

注意处理非法的状态,比如 $dp_{1,2}$ 是非法的。

#include<bits/stdc++.h>
using namespace std;
ifstream fin("word.in");
ofstream fout("word.out");
int n,m,k,dp[205][45],w[205][205];
string s,c[10];
inline int word(int l,int r){
    string x=s.substr(l,r-l+1);
    int ret=0,pos=0,lim=r-l;
    while(pos<=lim){
        int nxt=lim+5;
        for(int i=1;i<=m;i++){
            int now=x.find(c[i],pos);
            if(~now) nxt=min(nxt,now);
        }
        if(nxt<=lim) ++ret;
        pos=nxt+1;
    }
    return ret;
}
int main(){
    fin>>n>>k,s='#';
    for(int i=1;i<=n;i++){
        string x;
        fin>>x,s+=x;
    }
    fin>>m,n*=20;
    for(int i=1;i<=m;i++) fin>>c[i];
    for(int l=1;l<=n;l++)
        for(int r=l;r<=n;r++) w[l][r]=word(l,r);
    memset(dp,128,sizeof(dp));
    dp[0][0]=0;
    for(int l=1;l<=n;l++)
        for(int r=l;r<=n;r++)
            for(int i=1;i<=k;i++) dp[r][i]=max(dp[r][i],dp[l-1][i-1]+w[l][r]);
    fout<<dp[n][k]<<'\n';
    return 0;
}
最后修改:2024 年 08 月 16 日
如果觉得我的文章对你有用,请随意赞赏