hdu 4758 ac自动机+dp

明显dp[n][m][n1][m1][4] 表示用了n个R m个D,A串已经匹配了n1个B串匹配了m1,4种状态(0表示没有一个串已经匹配,1表示有第一串已经匹配了,2表示第二个串匹配,3表示2个串都匹配了)然而这个的负责度为100*100*100*100*4 数组都开不了,但是如果能借助ac自动机能把后面2维变成200表示在ac自动机的位置,用静态的ac自动机很好写,就是下标,

明显对于dp[i][j][dex][4]如果取R 能更新dp[i+1][j][nxt][?]4个状态要根据fail算出。nxt为加入R的自动机位置

如果取D能更新dp[i][j+1][nxt][?]

这种多字符串ac自动机能很好的减少维度

#include<cstdio>
#include<cstring>
#define M 201
#define kind 2
#define mod 1000000007
using namespace std;
int n,m;
int dp[102][102][M+1][4];
int dp1[M];
struct AC{
    int root,en,my_que[M];
    struct E{
        int flag,fail;
        int next[kind];
    }e[M];
    void flash(int id){
        e[id].flag=0;
        memset(e[id].next,-1,sizeof(e[id].next));
    }
    void init(){
        root=0;en=1;
        flash(root);
        e[root].fail=-1;
    }
    void insert(char *p,int id){
        int tr=root;
        for(int i=0;p[i];i++){
            int dex=p[i]-'a';
            if(e[tr].next[dex]==-1){
                int t2=en++;flash(t2);
                e[tr].next[dex]=t2;
            }
            tr=e[tr].next[dex];
        }
        e[tr].flag=id;
    }
    void build(){
        int hp=0,tp=-1;
        my_que[++tp]=root;
        while(tp>=hp){
            int now=my_que[hp++];
            for(int i=0;i<kind;i++){
                if(e[now].next[i]!=-1){
                    int nxt=e[now].next[i];
                    int dex=i;
                    if(now==root){
                        e[nxt].fail=root;
                    }
                    else{
                        int tmp=e[now].fail;
                        while(tmp!=-1&&e[tmp].next[dex]==-1) tmp=e[tmp].fail;
                        if(tmp==-1) tmp=root;
                        else tmp=e[tmp].next[dex];
                        e[nxt].fail=tmp;
                    }
                    my_que[++tp]=nxt;
                }
            }
        }
    }
    int dfs(int tmp){
        int ans=0;
        if(dp1[tmp]!=-1){
            return dp1[tmp];
        }
        ans|=e[tmp].flag;
        ans|=dfs(e[tmp].fail);
        return dp1[tmp]=ans;
    }
    int query(){
        for(int i=0;i<n+1;i++){
            for(int j=0;j<m+1;j++){
                for(int k=0;k<=n+m+1;k++){
                    for(int k1=0;k1<4;k1++){
                        dp[i][j][k][k1]=0;
                    }
                }
            }
        }
        dp[0][0][0][0]=1;
        memset(dp1,-1,sizeof(dp1));
        dp1[0]=0;
        for(int i=0;i<=n;i++){
            for(int j=0;j<=m;j++){
                for(int k=0;k<=n+m+1;k++){
                    for(int k1=0;k1<4;k1++){
                        if(dp[i][j][k][k1]==0) continue;
                        if(i<n){
                            int tr=k;
                            int dex=0;
                            while(e[tr].next[dex]==-1&&tr!=root) tr=e[tr].fail;
                            tr=e[tr].next[dex];
                            if(tr==-1) tr=root;
                            int tmp=tr;
                            int mark=k1|dfs(tmp);
                            dp[i+1][j][tr][mark]+=dp[i][j][k][k1];
                            dp[i+1][j][tr][mark]%=mod;
                        }
                        if(j<m){
                            int tr=k;
                            int dex=1;
                            while(e[tr].next[dex]==-1&&tr!=root) tr=e[tr].fail;
                            tr=e[tr].next[dex];
                            if(tr==-1) tr=root;
                            int tmp=tr;
                            int mark=k1|dfs(tmp);
                            dp[i][j+1][tr][mark]+=dp[i][j][k][k1];
                            dp[i][j+1][tr][mark]%=mod;
                        }
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<=n+m+1;i++){
            ans+=dp[n][m][i][3];
            ans%=mod;
        }
        return ans;
    }
}ac;
char str[M*2];
int main(){
    int cas;while(~scanf("%d",&cas)){
        while(cas--){
            ac.init();
            scanf("%d%d",&n,&m);
            scanf("%s",str);
            for(int i=0;str[i];i++){
                if(str[i]=='R') str[i]='a';
                else str[i]='b';
            }
            ac.insert(str,1);
            scanf("%s",str);
            for(int i=0;str[i];i++){
                if(str[i]=='R') str[i]='a';
                else str[i]='b';
            }
            ac.insert(str,2);
            ac.build();
            int ans=ac.query();
            printf("%d\n",ans);
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值