bzoj 1030
dp[i][j] 表示,在AC自动机中,从根节点开始,走了i条边,并且经过的点不包含危险节点,走到了j节点的路径数。
收获:
1、正难则反
2、一个字符串不包含给定pattern中的任何一个,则该字符串在AC自动机上走时不会走到“危险节点”。
3、DFS可以做的事情,可以考虑DP来做。
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <queue> 5 #define fprintf(...) 6 #define M 10007 7 #define maxn 6010 8 using namespace std; 9 10 int n, len; 11 int son[maxn][26], fail[maxn], ikey[maxn], ntot; 12 int dp[102][maxn]; 13 14 void insert( const char *P ) { 15 int n=strlen(P); 16 int u=0; 17 for( int i=0; i<n; i++ ) { 18 int c=P[i]-'A'; 19 if( !son[u][c] ) son[u][c]=++ntot; 20 fprintf( stderr, "%d->%d %c\n", u, son[u][c], c+'a' ); 21 u=son[u][c]; 22 } 23 ikey[u] = true; 24 } 25 void build() { 26 queue<int> qu; 27 for( int c=0; c<26; c++ ) { 28 int v=son[0][c]; 29 if( !v ) continue; 30 qu.push( v ); 31 fail[v] = 0; 32 fprintf( stderr, "fail[%d] = %d\n", v, fail[v] ); 33 } 34 while( !qu.empty() ) { 35 int u=qu.front(); 36 qu.pop(); 37 for( int c=0; c<26; c++ ) { 38 int v=son[u][c]; 39 int w=fail[u]; 40 if( !v ) { 41 son[u][c] = son[fail[u]][c]; 42 fprintf( stderr, "%d->%d %c\n", u, son[u][c], c+'a' ); 43 } else { 44 while( w && !son[w][c] ) w=fail[w]; 45 fail[v] = son[w][c]; 46 fprintf( stderr, "fail[%d] = %d\n", v, fail[v] ); 47 ikey[v] |= ikey[fail[v]]; 48 qu.push( v ); 49 } 50 } 51 } 52 } 53 void work() { 54 dp[0][0] = 1; 55 for( int i=0; i<=len; i++ ) 56 for( int u=0; u<=ntot; u++ ) 57 if( dp[i][u] ) { 58 fprintf( stderr, "dp[%d][%d] = %d\n", i, u, dp[i][u] ); 59 for( int c=0; c<26; c++ ) { 60 int v=son[u][c]; 61 if( ikey[v] ) continue; 62 dp[i+1][v] += dp[i][u]; 63 if( dp[i+1][v]>=M ) dp[i+1][v]-=M; 64 } 65 } 66 int ans = 1; 67 for( int i=1; i<=len; i++ ) 68 ans = (ans*26)%M; 69 for( int u=0; u<=ntot; u++ ) { 70 ans -= dp[len][u]; 71 if( ans<0 ) ans+=M; 72 } 73 printf( "%d\n", ans ); 74 } 75 int main() { 76 scanf( "%d%d", &n, &len ); 77 for( int i=1; i<=n; i++ ) { 78 char str[110]; 79 scanf( "%s", str ); 80 insert( str ); 81 } 82 build(); 83 work(); 84 }