[USACO12JAN]视频游戏的连击

一、题目

点此看题

二、解法

又是一道 AC \text{AC} 自动机上 d p dp 的题,随手乱切。

f [ i ] [ j ] f[i][j] 为长度为 i i ,在自动机上匹配到 j j 点的最大值,一开始全赋最小值,在 f a i l fail 树上求一个链的前缀和,直接转移即可,时间复杂度 O ( 3 × 15 × n k ) O(3\times 15\times nk) ,贴个代码。

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int M = 305;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m,ans,f[1005][M];
char s[M];
struct Automaton
{
    int c[M][26],val[M],fail[M],cnt;
    void ins(char *s)
    {
        int len=strlen(s),now=0;
        for(int i=0; i<len; i++)
        {
            int v=s[i]-'A';
            if(!c[now][v]) c[now][v]=++cnt;
            now=c[now][v];
        }
        val[now]++;
    }
    void build()
    {
        queue<int> q;
        for(int i=0; i<26; i++) if(c[0][i]) q.push(c[0][i]);
        while(!q.empty())
        {
            int t=q.front();
            q.pop();
            for(int i=0; i<26; i++)
                if(c[t][i])
                {
                    fail[c[t][i]]=c[fail[t]][i];
                    val[c[t][i]]+=val[fail[c[t][i]]];
                    q.push(c[t][i]);
                }
                else c[t][i]=c[fail[t]][i];
        }
    }
    void dp()
    {
        memset(f,-0x3f,sizeof f);
        f[0][0]=0;
        for(int i=0; i<m; i++)
        {
            for(int j=0; j<=cnt; j++)
            {
                for(int k=0; k<3; k++)
                {
                    f[i+1][c[j][k]]=max(f[i+1][c[j][k]],f[i][j]+val[c[j][k]]);
                }
            }
        }
        for(int j=0; j<=cnt; j++)
            ans=max(ans,f[m][j]);
        printf("%d\n",ans);
    }
} AC;
int main()
{
    n=read();
    m=read();
    for(int i=1; i<=n; i++)
    {
        scanf("%s",s);
        AC.ins(s);
    }
    AC.build();
    AC.dp();
}
发布了257 篇原创文章 · 获赞 13 · 访问量 6749

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/104119502