3472. 【NOIP2013模拟联考8】匹配(match)

Description

给定k个字符串以及长度为n的母串可选字母的集合,问母串要完整出现给定的k个字符串的方案数,答案模1000000007,字符仅包含小写字母。

Input

第一行两个整数n、k,表示字符串的长度和给定字符串的个数。

接下来k行每行一个字符串。

接下来一行1个整数m表示可选字母集合内元素个数。

接下来一行给出一个长为m的字符串,表示字母的集合(可能有重复)。

Output

一个整数ans,表示方案数。

Sample Input

3 2

cr

rh

4

acrh

Sample Output

1

【样例解释】

只有crh符合。

Data Constraint

30%的数据n<=10,m<=3。

60%的数据n<=40。

另有10%的数据k=0。

另有10%的数据m=1。

100%的数据n<=100,m<=10,k<=8,给定字符串长度<=30。
想法:
建一棵trie,然后进行AC自动机
字典树中,fail指针表示fail指针到根的字符串,是这个点到根的字符串的后缀,
这可以通过每个点的父亲的fail指针求得
然后预处理出son[i][j]表示第i个点,当下一个与它连接的字符为j是,j的位置
还有str[i]表示到i这个点是,i到根的字符串包括了哪些字符串的状态
比如说abcd包括了bc,
这样就可以dp了,设f[i][j][s]表示构造到第i位,第i位在trie上的位置为j,所选字符串状态为s的方案数

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#define ll long long
using namespace std;
const ll maxN=101,maxM=11,maxK=9,maxS=256,maxn=1000000007;
char s[9][31],s1[11],ch;

ll tail[9],n,k,m,i,f[110][250][256],cnt,tot,
last[250],next[250],tov[250],j,len,l,y,q,
to[250][27],s2,s3,ans,ch1,fail[250],fa[250],str[250];
struct zhj{
    char x;
};
zhj a[250];
void insert(ll x,ll y){
    tov[++tot]=y,next[tot]=last[x],last[x]=tot;
}
int main(){
    //freopen("a.in","r",stdin);
    scanf("%lld%lld",&n,&q);
    for (i=1;i<=q;i++){
        scanf("%s",s[i]+1);
        k=0;
        len=strlen(s[i]+1);
        for (j=1;j<=len;j++){
            for (l=last[k];l>0;l=next[l]){
                y=tov[l];
                if (a[y].x==s[i][j]){
                    break;
                }
            }
            if (l>0){
                k=y;
            }else{
                cnt++,a[cnt].x=s[i][j],insert(k,cnt),fa[cnt]=k, k=cnt;
            }
        }
        str[k]+=1<<i-1;
        scanf("\n");
    }
    scanf("%d",&m);
    scanf("%s",s1+1);
    for (i=1;i<=cnt;i++){
        j=fa[i];
        while (j!=0){
            j=fail[j];
            for (k=last[j];k>0;k=next[k]){
                y=tov[k];
                if (a[y].x==a[i].x){
                    fail[i]=y;
                    break;
                }
            }
            if (fail[i]>0) break;
        }
        to[fa[i]][a[i].x-'a'+1]=i;
    }
    for (i=0;i<=cnt;i++){
        str[i]=str[fail[i]]|str[i];
    }
    for (i=1;i<=cnt;i++){
        for (ch=1;ch<=26;ch++){
            if (to[i][ch]>0) continue;
            j=i;
            while (j!=0){
                for (k=last[j];k>0;k=next[k]){
                    y=tov[k],l=a[y].x-'a'+1;
                    if (l==ch){
                        to[i][ch]=y;
                        break;
                    }
                }
                if (to[i][ch]>0) break;
                j=fail[j];
            }   
            if (to[i][ch]>0) continue;
            for (k=last[0];k>0;k=next[k]){
                y=tov[k],l=a[y].x-'a'+1;
                if (l==ch){
                    to[i][ch]=y;
                    break;
                }   
            }
        }
    }
    memset(f,0,sizeof(f));
    f[0][0][0]=1;
    for (i=0;i<=n-1;i++){
        for (j=0;j<=cnt;j++){
            for (s2=0;s2<=(1<<q)-1;s2++){
                if (f[i][j][s2]==0) continue;
                for (ch1=1;ch1<=m;ch1++){
                    ch=s1[ch1]-'a'+1,s3=s2,y=to[j][ch];     
                    f[i+1][y][s3|str[y]]=(f[i+1][y][s3|str[y]]+f[i][j][s2])%maxn;
                }
            }
        }
        ch=1;
    }
    ans=0;
    for (i=0;i<=cnt;i++){
        ans=(ans+f[n][i][(1<<q)-1])%maxn;
    }
    printf("%lld",ans);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章