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

来源:互联网 发布:电脑视频文件恢复软件 编辑:程序博客网 时间:2024/05/29 14:46

挺明显的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 0xc3c3c3c3using 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);}
原创粉丝点击