hdu4758 AC自动机+dp

不用AC自动机的话,怎么dp,推公式都会交叉,都会重复,只有用AC自动机分离出一个个匹配的状态才能解决

此题是poj2778 DNA sequence的弱化版

1.对自动机上每个状态dp,dp[a][b][c][d]表示经过了a个字符,匹配了b个R,在c这个状态,d是4进制数,表示是否经过串1和串2

trie树上其实代表一种转移关系,即当前匹配了i个字符,遇到i+1个字符会转到哪个状态

2.深刻理解fail指针,点u的fail指针,即到达状态u,也就到达状态fail[u],所以val[u]|=val[fail[u]]

在求fail要用到一个优化,补齐不存在的边,直接fail[ch[u][i]]=ch[fail[u]][i],不用while(p&&!ch[p][i]) p=fail[p],那样很慢

考虑现在状态u上,下个字符是R,R边存在,u状态上的值直接加到与R边相连的儿子;

如果下个字符时D,D边不存在,u的下个状态nxt,是u沿着失配指针一直走,途中经过很多状态p,某个p的D边存在,这个p就是nxt;

假如有这个优化就不用每次while(p&&!ch[p][i]) p=fail[p]一直走,不然会TLE

卡着时间过,用指针版会快点


#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
#include <algorithm>
using namespace std;
#define mod 1000000007
#define ll long long
#define CH 2
#define N 250
int ch[N][CH],fail[N],sz,val[N],que[N],sw[300];
ll dp[2][N/2][N][4];
void _insert(char *s,int idx)
{
    int p=0;
    for(int i=0;s[i]!='\0';++i)
    {
        if(ch[p][sw[s[i]]]==0)
            ch[p][sw[s[i]]]=sz++;
        p=ch[p][sw[s[i]]];
    }
    val[p]=idx;
}
void getfail()
{
    int front=0,rear=0;
    for(int i=0;i<CH;++i)
        if(ch[0][i])
    {
        que[rear++]=ch[0][i];
        fail[ch[0][i]]=0;
    }
    while(front<rear)
    {
        int u=que[front++];
        for(int i=0;i<CH;++i)
            if(ch[u][i])
        {
            que[rear++]=ch[u][i];
            fail[ch[u][i]]=ch[fail[u]][i];
            val[ch[u][i]]|=val[ch[fail[u]][i]];
        }
        else ch[u][i]=ch[fail[u]][i];
    }
}
void init()
{
    memset(ch,0,sizeof(ch));
    memset(val,0,sizeof(val));
    sz=1;
}
char str[200];
int m,n;
int main ()
{
    sw['R']=0;sw['D']=1;
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&m,&n);
        init();
        scanf("%s",str);
        _insert(str,1);
        scanf("%s",str);
        _insert(str,2);
        getfail();

        memset(dp,0,sizeof(dp));
        dp[0][0][0][0]=1;

        for(int tt=0;tt<m+n;++tt) // tt -> tt+1
        {
            memset(dp[(tt+1)%2],0,sizeof(dp[(tt+1)%2]));
            for(int sta=0;sta<sz;++sta)
            {
                for(int j=0;j<=m;++j)
                    for(int r=0;r<4;++r)
                {
                    for(int k=0;k<CH;++k)
                    {
                        int mm=k==0?1:0; // sw['R']=0
                        int nxt=ch[sta][k];
                        dp[(tt+1)%2][j+mm][nxt][r|val[nxt]]+=dp[tt%2][j][sta][r];
                        if( dp[(tt+1)%2][j+mm][nxt][r|val[nxt]]>=mod)
                             dp[(tt+1)%2][j+mm][nxt][r|val[nxt]]%=mod;
                    }
                }
            }
        }
        ll ans=0;
        for(int i=0;i<sz;++i)
        {
            ans+=dp[(m+n)%2][m][i][3];
            if(ans>=mod) ans%=mod;
        }
        cout<<ans<<endl;
    }
    return 0;
}



你可能感兴趣的:(hdu4758 AC自动机+dp)