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

该博客探讨了一道编程问题,涉及使用n个R和m个D组成字符串,同时包含两个不同的只包含R或D的字符串s1和s2。解决方法是构建优化了失配函数的AC自动机,即Trie图。通过动态规划(DP)策略,初始化状态并自顶向下进行DP,最终统计满足条件的字符串总数。
摘要由CSDN通过智能技术生成

      提议大致是给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;
}


         

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值