1. 程式人生 > >bzoj 1030 [JSOI2007]文本生成器 (Trie圖+DP)

bzoj 1030 [JSOI2007]文本生成器 (Trie圖+DP)

jsoi2007 noi2008 道理 color https 模式 bzoj tps pre

題目大意:給你一堆字符串,一個串不合法的條件是這些字符串中任意一個是這個串的子串,求合法的串的數量

其實這道題比 [HNOI2008]GT考試 那道題好寫一些,但道理是一樣的

只不過這道題的答案可以轉化為 所有可能的字符串(26^m)數量 - 不合法的字符串數量

定義f[i][j]表示匹配到了第i個字符,現在在Trie樹上匹配到了第j個節點的方案數

GT考試是跳Next,每次找出 和 插入這個字符後形成的字符串 具有相同最長後綴的位置

那麽對於Trie圖來說,這不就是fail指針麽

Trie樹被補全成Trie樹後

如果在原來的Trie樹中某個節點x,它並沒有兒子ch[x][c],那麽在補全後,ch[x][c]自動指向的是x的fail指針指向的c兒子,即ch[fail[x]][c]

這不正是我們想要轉移的位置麽,非常智能

總結:字符串套KMP/AC自動機/Trie圖的題,通常都有f[i][j]表示文本串匹配到了第i位,模式串匹配到了第j位這類狀態,且有一些題可以用矩陣乘法優化。

 1 #include <queue>
 2 #include <cmath>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 #define ll long long 
 7 #define N 6010
 8 #define M 28
 9 #define
mod 10007 10 #define ui unsigned int 11 #define idx(x) (x-‘A‘+1) 12 #define inf 0x3f3f3f3f 13 using namespace std; 14 //re 15 int n,m; 16 char str[65][110]; 17 int f[120][N]; 18 int qpow(int x,int y){ 19 int ans=1; 20 while(y){ 21 if(y&1) ans=(ans*x)%mod; 22 x=(x*x)%mod,y>>=1
; 23 }return ans; 24 } 25 struct Trie{ 26 int ch[N][M],fa[N],fail[N],ed[N],tot; 27 void Build() 28 { 29 for(int i=1;i<=n;i++) 30 { 31 int len=strlen(str[i]+1),x=0; 32 for(int j=1;j<=len;j++) 33 { 34 int c=idx(str[i][j]); 35 if(!ch[x][c]) 36 tot++,ch[x][c]=tot,fa[tot]=x; 37 x=ch[x][c]; 38 if(j==len) ed[x]=1; 39 } 40 } 41 } 42 void Fail() 43 { 44 queue<int>q; 45 for(int i=1;i<=26;i++) 46 if(ch[0][i]) q.push(ch[0][i]); 47 while(!q.empty()) 48 { 49 int x=q.front();q.pop(); 50 for(int i=1;i<=26;i++) 51 if(ch[x][i]) 52 fail[ch[x][i]]=ch[fail[x]][i], 53 q.push(ch[x][i]); 54 else 55 ch[x][i]=ch[fail[x]][i]; 56 } 57 } 58 int solve() 59 { 60 f[0][0]=1; 61 queue<int>q; 62 for(int i=0;i<=m;i++) 63 for(int x=0;x<=tot;x++) 64 for(int c=1;c<=26;c++) 65 { 66 int flag=1; 67 for(int k=ch[x][c];k;k=fail[k]) 68 if(ed[k]){flag=0;break;} 69 if(!flag) continue; 70 (f[i+1][ch[x][c]]+=f[i][x])%=mod; 71 } 72 int ans=0; 73 for(int x=0;x<=tot;x++) 74 if(!ed[x]) (ans+=f[m][x])%=mod; 75 return ans; 76 } 77 }t; 78 int main() 79 { 80 scanf("%d%d",&n,&m); 81 for(int i=1;i<=n;i++) scanf("%s",str[i]+1); 82 t.Build(); 83 t.Fail(); 84 printf("%u\n",(qpow(26,m)-t.solve()+mod)%mod); 85 return 0; 86 }

bzoj 1030 [JSOI2007]文本生成器 (Trie圖+DP)