bzoj 1030 文字生成器(AC自動機+dp)
阿新 • • 發佈:2018-12-12
前置知識ac自動機或者trie圖。
根據題意需要求出文章中包含1個或更多的字串的數量。但是這明顯很難求,所以求出所有方案減去不包含的數量。
考慮dp,設f[i][j]表示第i位置時為AC自動機(trie圖)上第j個字元沒有匹配的方案數,如果這個字元的下一個字元沒有匹配就可以
轉移,預處理那些字元可以匹配只需在求fail指標的時候繼承一下fail指標的狀態即可。
我寫的trie圖
程式碼
#include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #include<queue> #define mode 10007 using namespace std; char ss[65][150]; int t[60105][27]; int fail[60105]; int f[105][60105]; int fin[60105]; int l,sz; void insert(char *s) { l=strlen(s); int root=0,k; for(int i=0;i<l;i++) { k=s[i]-'A'; if(!t[root][k])t[root][k]=++sz; root=t[root][k]; } fin[root]++; } queue<int>M; void get_fail() { int root=0; for(int i=0;i<26;i++) { if(t[root][i])M.push(t[root][i]); } while(!M.empty()) { root=M.front();M.pop(); for(int i=0;i<26;i++) { if(t[root][i]) { fail[t[root][i]]=t[fail[root]][i]; fin[t[root][i]]+=fin[t[fail[root]][i]]; M.push(t[root][i]); }else { t[root][i]=t[fail[root]][i]; } } } } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",ss[i]); insert(ss[i]); } get_fail(); f[0][0]=1; for(int i=1;i<=m;i++) { for(int j=0;j<=sz;j++) { for(int k=0;k<26;k++) { if(!fin[t[j][k]]) { f[i][t[j][k]]+=f[i-1][j]; f[i][t[j][k]]%=mode; } } } } int ans=0; for(int i=0;i<=sz;i++) { ans+=f[m][i]; ans%=mode; } int sum=1; for(int i=1;i<=m;i++) { sum=sum*26%mode; } printf("%d",((sum-ans)%mode+mode)%mode); return 0; }