bzoj2580 [Usaco2012 Jan]Video Game AC自动机+dp

168 篇文章 0 订阅
12 篇文章 0 订阅

挺明显的dp,设f[i][j]表示走到第i个位置,trie上的第j个节点的最大答案,把每个结尾+1然后求出前缀和,直接更新就可以了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define inf 0xc3c3c3c3
using namespace std;
const int N=1e5+5;
int ch[N][5];
char s[N];
int tag[N],cnt=1;
int fail[N],q[N];
int f[1005][500];
int num[N];
int n,K;
inline void add(int x,int k)
{
    memset(ch[cnt],0,sizeof(ch[cnt]));
    num[cnt]=0;
    ch[x][k]=cnt++;
}
inline void ins()
{
    int n=strlen(s);
    int x=0;
    fo(i,0,n-1)
    {
        int c=s[i]-'A';
        if (!ch[x][c])add(x,c);
         x=ch[x][c];
    }
    num[x]++;
}
inline void acmach()
{
    int w=1;
    int x;
    q[0]=0; 
    fo(i,0,w-1)
    { 
        x=q[i];
        num[x]+=num[fail[x]];
        fo(j,0,2)
        if (ch[x][j])
        {
            q[w++]=ch[x][j];
            if (!x)fail[ch[x][j]]=0;
            else fail[ch[x][j]]=ch[fail[x]][j];
        }
        else ch[x][j]=ch[fail[x]][j];
    }
}
inline void dp()
{
    memset(f,0xc3,sizeof(f));
    f[0][0]=0;
    fo(i,0,K-1)
    fo(j,0,cnt-1)
    if (f[i][j]!=inf)
    fo(k,0,2)
    {
        int x=ch[j][k];
        f[i+1][x]=max(f[i+1][x],f[i][j]+num[x]);
    }//f[i][ch[j][k]]=max(f[i][ch[j][k]],f[i-1][j]+num[ch[j][k]]);
}
int main()
{
    scanf("%d%d",&n,&K);
    num[0]=0;
    memset(ch[0],0,sizeof(ch[0]));
    cnt=1;
    fo(i,1,n)
    {
        scanf("%s",s);
        ins();
    }
    acmach();
    dp();
    int ans=0;
    fo(i,0,cnt-1)ans=max(ans,f[K][i]);
    printf("%d\n",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值