hdu 4758 Walk Through Squares AC自动机

题意:

在一个(n+1)*(m+1)的矩阵中从0点到(n+1)(m+1)点,每次只能向左走或者向下走,问所有走法中包含所给出的2种子串的走法有多少种。

分析:

     AC自动机类的题目做多了,就能看出这类题的套路。可以根据这2个子串建立tire图然后记dp【x】【y】【t】【k】表示向左走x步右走y步到达自动机t节点时候为状态k(0<=k<4)(0-->不包含任何子串,1-->只包含第一种子串,2-->只包含第二种子串,3-->都包含)

ACcode:

#include <bits/stdc++.h>
#define mod 1000000007
using namespace std;
int N,M,loop;
char str[101];
int dp[101][101][202][4];
struct Aho{
    struct state{
        int next[2];
        int fail,cnt;
    }s[202];
    queue<int>q;
    int size;
    void init(){
        while(q.size())q.pop();
        for(int i=0;i<202;++i){
            memset(s[i].next,-1,sizeof(s[i].next));
            s[i].fail=s[i].cnt=0;
        }
        size=1;
    }
    void  insert(char *str,int t){
        int now=0;
        int n=strlen(str);
        for(int i=0;i<n;++i){
            int id=0;
            if(str[i]=='D')id=1;
            if(s[now].next[id]==-1)
            s[now].next[id]=size++;
            now=s[now].next[id];
        }
        s[now].cnt|=t;
    }
    void build(){
        s[0].fail=0;
        for(int i=0;i<2;++i){
            if(s[0].next[i]==-1)
                s[0].next[i]=0;
            else {
                s[s[0].next[i]].fail=0;
                q.push(s[0].next[i]);
            }
        }
        while(q.size()){
            int u=q.front();
            q.pop();s[u].cnt|=s[s[u].fail].cnt;
            for(int i=0;i<2;++i){
                if(s[u].next[i]==-1)
                    s[u].next[i]=s[s[u].fail].next[i];
                else{
                    s[s[u].next[i]].fail=s[s[u].fail].next[i];
                    q.push(s[u].next[i]);
                }
            }
        }
        for(int i=0;i<=N;++i)
            for(int j=0;j<=M;++j)
                for(int t=0;t<=size;++t)
                    for(int k=0;k<4;++k)
                        dp[i][j][t][k]=0;
        dp[0][0][0][0]=1;
        for(int i=0;i<=N;++i)
            for(int j=0;j<=M;++j)
                for(int t=0;t<size;++t)
                    for(int k=0;k<4;++k){
                        if(dp[i][j][t][k]==0)continue;
                        if(i<N)
                            dp[i+1][j][s[t].next[0]][k|s[s[t].next[0]].cnt]=(dp[i+1][j][s[t].next[0]][k|s[s[t].next[0]].cnt]+dp[i][j][t][k])%mod;
                        if(j<M)
                            dp[i][j+1][s[t].next[1]][k|s[s[t].next[1]].cnt]=(dp[i][j+1][s[t].next[1]][k|s[s[t].next[1]].cnt]+dp[i][j][t][k])%mod;
                    }
        int ans=0;
        for(int i=0;i<size;++i)
            ans=(ans+dp[N][M][i][3])%mod;
        printf("%d\n",ans);
    }
}aho;
int main(){
    scanf("%d",&loop);
    while(loop--){
        scanf("%d%d",&N,&M);
        aho.init();
        scanf("%s",str);
        aho.insert(str,1);
        scanf("%s",str);
        aho.insert(str,2);
        aho.build();
    }
    return 0;
}
/*
10
3 3
DDR
RR
4 4
DDR
RR
5 5
DDR
RR
6 6
DDR
RR
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值