BZOJ 1030 [JSOI2007]文本生成器 (Trie图+DP)
题目大意:给你一堆字符串,一个串不合法的条件是这些字符串中任意一个是这个串的子串,求合法的串的数量
其实这道题比 [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 }