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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章