hdu4758 Walk Through Squares AC自动机(trie图)DP

来源:互联网 发布:最新金山画王软件 编辑:程序博客网 时间:2024/06/12 05:21

      提议大致是给n,m,再给两个非空的不相同的只包含R或D字符串s1,s2,问用n个R,m个D可以组成多少种包含s1,s2的字符串。大致思路的话,先根据两个字符串构造trie图,其实就是把失配函数优化掉的ac自动机。之后用dp[i][x][y][k]表示在自动机上状态i,用x个R,y个D,包含s1,s2的状态.令初值dp[0][0][0][0]=1,向上DP,最后统计dp[i][n][m][3](0<=i<top)的和即可。

     

#include <iostream>#include <algorithm>#include <cstdio>#include <memory.h>#include <string>#include <cstring>#include <queue>using namespace std;typedef long long ll;const int maxn=420;const int tk=2;int tree[maxn][tk];int val[maxn];int last[maxn];int f[maxn];int n,m,p,q,k;int top;int dp[220][110][110][4];int ok[maxn];const int mod=1000000007;inline int idx(char s){    if (s=='R') return 0;    return 1;}struct autoAC{    void init()    {        top=1;        tree[0][0]=tree[0][1]=0;        memset(val,0,sizeof val);        memset(f,0,sizeof f);        memset(last,0,sizeof last);    }    void insert(char* s,int rank)    {        int rt,nxt;        for (rt=0; *s; rt=nxt,++s)        {            nxt=tree[rt][idx(*s)];            if (nxt==0)            {                tree[rt][idx(*s)]=nxt=top;                tree[top][0]=tree[top][1]=0;                top++;            }        }        val[rt]=rank;    }    void getFail()    {        queue<int> q;        f[0]=0;        for (int c=0; c<tk; c++)        {            int u=tree[0][c];            if (u)            {                q.push(u);                f[u]=0;                last[u]=0;            }        }        while(!q.empty())        {            int r=q.front();            q.pop();            for (int c=0; c<tk; c++)            {                int u=tree[r][c];                if (!u)                {                    tree[r][c]=tree[f[r]][c];                    continue;                }                q.push(u);                int v=f[r];                while(v && !tree[v][c]) v=f[v];                f[u]=tree[v][c];                last[u]=val[f[u]]? f[u] : last[f[u]];            }        }    }}ac;int tt;int mx,my;char s[105],ss[105],str[105];inline void work(){    memset(ok,0,sizeof ok);    for (int i=0; i<top; i++)    {        int j=last[i];        ok[i]=val[i];        while(j)        {            ok[i]=ok[i]|val[j];            j=last[j];        }    }    dp[0][0][0][0]=1;    int sta;    for (int x=0; x<=mx; x++)     for (int y=0; y<=my; y++)     for (int i=0; i<top; i++)     for (int k=0; k<4; k++)     {         if (dp[i][x][y][k]==0) continue;         if (x<mx)         {             int nxt=tree[i][0];              sta=k|ok[nxt];             dp[nxt][x+1][y][sta]+=dp[i][x][y][k];             if (dp[nxt][x+1][y][sta]>=mod) dp[nxt][x+1][y][sta]-=mod;         }         if (y<my)         {             int nxt=tree[i][1];              sta=k|ok[nxt];             dp[nxt][x][y+1][sta]+=dp[i][x][y][k];             if (dp[nxt][x][y+1][sta]>=mod) dp[nxt][x][y+1][sta]-=mod;         }     }     ll res=0;     for (int i=0; i<top; i++)     {         res+=dp[i][mx][my][3];//         if (res>=mod) res-=mod;     }     res%=mod;     cout<<res<<endl;}int main(){//    freopen("in.txt","r",stdin);    scanf("%d",&tt);    while(tt--)    {        ac.init();        scanf("%d%d",&mx,&my);        for (int i=1; i<=2; i++)        {            scanf("%s",s);            ac.insert(s,i);        }        ac.getFail();        memset(dp,0,sizeof dp);        work();    }    return 0;}


         

原创粉丝点击