題解[ [JSOI2007]文字生成器 ]
阿新 • • 發佈:2021-07-26
題目
給定\(n\)個模式串,求長度為\(m\)且不含模式串的文字串個數。
Sol
學習AC自動機的時候刷到了這道題.
看網上的各種題解,發現這類AC自動機上DP都是一種類似的套路。
首先,設\(f[i][j]\)表示匹配到長度為\(i\)的地方,匹配到AC自動機上的第\(j\)個節點且不含模式串的方案數。
由於我們正向算方案容易算重,所以考慮求不含模式串的文字串數量。
設輔助陣列\(sz[id]\)表示在AC自動機上的第\(id\)個節點之前是否已經含有至少一個模式串。
設\(nx[i][j]\)表示AC自動機上第\(i\)個節點,且下一個字元為\(j\)的後繼節點。
那麼:
\[if(!sz[j][k])\ f[i][nx[j][k]]+=f[i-1][j] \]列舉一下就好了。
Code
#include<bits/stdc++.h> #define N (61) #define M (10010) using namespace std; const int P=10007; int n,m,f[110][M]; char ss[M]; inline int read(){ int w=0; char ch=getchar(); while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9'){ w=(w<<3)+(w<<1)+(ch^48); ch=getchar(); } return w; } struct Aho_C{ int tot,nx[M][26],sz[M],fail[M]; inline void insert(){ scanf("%s",ss); int pos=0; for(int i=0;i<(int)strlen(ss);i++){ if(!nx[pos][ss[i]-'A']) nx[pos][ss[i]-'A']=++tot; pos=nx[pos][ss[i]-'A']; } sz[pos]|=1; return; } inline void build(){ queue<int>q; for(int i=0;i<26;i++) if(nx[0][i]) q.push(nx[0][i]); while(!q.empty()){ int pos=q.front(); q.pop(); for(int i=0;i<26;i++){ if(nx[pos][i]){ sz[nx[pos][i]]|=sz[nx[fail[pos]][i]]; fail[nx[pos][i]]=nx[fail[pos]][i]; q.push(nx[pos][i]); } else nx[pos][i]=nx[fail[pos]][i]; } } return; } inline void DP(){ int ans=0,res=1; f[0][0]=1; for(int i=1;i<=m;i++) for(int j=0;j<=tot;j++) for(int k=0;k<26;k++) if(!sz[nx[j][k]]) f[i][nx[j][k]]=(f[i][nx[j][k]]+f[i-1][j])%P; for(int i=0;i<=tot;i++) ans=(ans+f[m][i])%P; for(int i=1;i<=m;i++) res=res*26%P; printf("%d\n",(res-ans+P)%P); return; } }AC; int main(){ n=read(),m=read(); for(int i=1;i<=n;i++) AC.insert(); AC.build(); AC.DP(); return 0; }