专栏文章

题解:P1026 [NOIP 2001 提高组] 统计单词个数

P1026题解参与者 5已保存评论 4

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
4 条
当前快照
1 份
快照标识符
@mipohx4r
此快照首次捕获于
2025/12/03 15:21
3 个月前
此快照最后确认于
2025/12/03 15:21
3 个月前
查看原文
废话不多说,多说的不是废话,我们直接进入正题。
题目简化: 没什么好简化的,自己看题目去。
首先,让我们来回顾一下区间 DP 的知识。
区间 DP,即对一个区间内的元素进行合并或拆分的操作,在满足要求的前提下求出最小(或最大)代价。
好,让我们回到这道题上。题目中的“分割成 kk 个部分”这句话,看上去不就很像一个区间 DP 吗?因为这是分割型 DP(具体定义详见这篇文章),所以我们定义的 DP 状态 dpi,jdp_{i,j} 表示前 ii 个字符分割成 jj 个区间的最大个数,那么状态转移方程就可以写成这样:
dpi,j=maxji{dpk1,j1+ak,i}dp_{i,j}=\max^i_j\{dp_{k-1,j-1}+a_{k,i}\}
其中 ai,ja_{i,j} 表示从第 ii 个字符到第 jj 个字符中的单词数。
现在我们就需要考虑一下这个 ai,ja_{i,j} 怎么求了。
我这里提供一种思路:我们可以把 ai,ja_{i,j} 也当做一个 DP,那么 ai,ja_{i,j} 首先就肯定要继承上一个状态,即 ai,j=ai,j1a_{i,j}=a_{i,j-1},然后我们看看当前从 iijj 这个字符串中有没有单词。
但我相信很多人都能看出来其中的问题:这个字符串里的同一个单词在上次和这次会被重复计算。我又想到了一个办法:我只需要找后几个字母构成的“词”是不是单词就行了,而这个“词”的长度就是单词的长度。
由于本人怕跑循环会 TLE,但又不会哈希,于是决定用 STL,不会 STL 中的 stringfind 的用法的同学见这篇文章
代码:
CPP
#include<bits/stdc++.h>
#define int long long
#define npos string::npos
using namespace std;
int n,m,kk,vis[206],siz[16],a[206][206],dp[206][46];
string s,ss[16];
signed main()
{
    s+=" ";
    cin>>m>>kk;
    while(m--)
    {
        string t="";
        cin>>t;
        s+=t;
    }
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        cin>>ss[i];
        siz[i]=ss[i].size();
    }
    n=s.size()-1;//这里注意!!!
    for(int i=1;i<=n;i++)
    {
        string t="";
        memset(vis,0,sizeof(vis));
        for(int j=i;j<=n;j++)
        {
            a[i][j]=a[i][j-1];
            t+=s[j];
            int l=t.size();
            for(int k=1;k<=m;k++)
            {
                if(l-siz[k]<0||vis[l-siz[k]])
                {
                    continue;
                }
                if(t.rfind(ss[k])==l-siz[k])//详见上面的文章
                {
                    a[i][j]++;
                    vis[l-siz[k]]=1;
                }
            }
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=min(i,kk);j++)
        {
            for(int k=j;k<=i;k++)
            {
                dp[i][j]=max(dp[i][j],dp[k-1][j-1]+a[k][i]);
            }
        }
    }
    cout<<dp[n][kk];
    return 0;
}

评论

4 条评论,欢迎与作者交流。

正在加载评论...