Gym 101174 E - Passwords —— AC自动机+状压DP

This way

题意:

给出 n 个字符串黑名单,要求组成长度为 a b a-b 的字符串,其中不能包含这n个字符串的任意一种,并且至少有一个大写字母,一个小写字母,一个数字,并且所包含的所有字符也只能是字母与数字。其中相似字符算同一种字符,即在匹配时是一致的,所有字母大小写相似, 0 o , 1 i , 3 e , 5 s , 7 t 0-o,1-i,3-e,5-s,7-t 也相似,但是在计算答案的时候,它们是不一样的。

题解:

看这个输入感觉像是AC自动机,但是其实进一步想下去一时间想不到,然后就去看题解了。
先建立AC自动机,然后dp[i][j][k]表示当前到了第i位,在AC自动机上的位置为j的时候,三种数包含的状态为k的时候的情况数。
然后枚举下一个数是什么进行转移。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e3+5,R=26;
const int mod=1e6+3;
int tot;
struct Tire{
    int nxt[N][R],fail[N],ed[N],num[N];
    int rt;
    int newnode(){
        for(int i=0;i<R;i++)nxt[tot][i]=-1;
        ed[tot]=0;
        return tot++;
    }
    void init(){
        memset(num,0,sizeof(num));
        tot=0;
        rt=newnode();
    }
    int insert(char *s){
        int now=rt,len=strlen(s);
        for(int i=0;i<len;i++){
            int val=s[i]-'a';
            if(nxt[now][val]==-1)nxt[now][val]=newnode();
            now=nxt[now][val];
        }
        ed[now]=1;
        return now;
    }
    void build(){
        queue<int>q;
        fail[rt]=rt;
        for(int i=0;i<R;i++){
            if(nxt[rt][i]==-1)nxt[rt][i]=rt;
            else {
                fail[nxt[rt][i]]=rt;
                q.push(nxt[rt][i]);
            }
        }
        while(!q.empty()){

            int now=q.front();q.pop();
            ed[now]|=ed[fail[now]];
            for(int i=0;i<R;i++){
                if(nxt[now][i]==-1)nxt[now][i]=nxt[fail[now]][i];
                else {
                    fail[nxt[now][i]]=nxt[fail[now]][i];
                    q.push(nxt[now][i]);
                }
            }
        }
    }
}ac;
char s[N],ss[N];
int cng[]={'o'-'a','i'-'a',-1,'e'-'a',-1,'s'-'a',-1,'t'-'a',-1,-1};
int dp[25][N][8];
int main()
{
    int n,l,r;
    scanf("%d%d%d",&l,&r,&n);
    ac.init();
    for(int i=1;i<=n;i++)
        scanf("%s",s),ac.insert(s);
    ac.build();
    memset(dp,-1,sizeof(dp));
    dp[0][0][0]=1;
    for(int i=0;i<r;i++){
        for(int j=0;j<=7;j++){
            for(int k=0;k<tot;k++){
                if(dp[i][k][j]==-1)continue;
                for(int c=0;c<=25;c++){
                    int ne=ac.nxt[k][c];
                    if(ac.ed[ne])continue;
                    if(dp[i+1][ne][j|1]==-1)dp[i+1][ne][j|1]=0;
                    dp[i+1][ne][j|1]=(dp[i+1][ne][j|1]+dp[i][k][j])%mod;
                }
                for(int c=0;c<=25;c++){
                    int ne=ac.nxt[k][c];
                    if(ac.ed[ne])continue;
                    if(dp[i+1][ne][j|2]==-1)dp[i+1][ne][j|2]=0;
                    dp[i+1][ne][j|2]=(dp[i+1][ne][j|2]+dp[i][k][j])%mod;
                }
                for(int c=0;c<=9;c++){
                    int ne;
                    if(cng[c]==-1)
                        ne=0;
                    else
                        ne=ac.nxt[k][cng[c]];
                    if(ac.ed[ne])continue;
                    if(dp[i+1][ne][j|4]==-1)dp[i+1][ne][j|4]=0;
                    dp[i+1][ne][j|4]=(dp[i+1][ne][j|4]+dp[i][k][j])%mod;
                }
            }
        }
    }
    int ans=0;
    for(int i=l;i<=r;i++)
        for(int j=0;j<tot;j++)
            if(~dp[i][j][7])
                ans=(ans+dp[i][j][7])%mod;
    printf("%d\n",ans);
    return 0;
}


发布了584 篇原创文章 · 获赞 33 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/tianyizhicheng/article/details/105256297