bzoj 2938
收获:
1、AC自动机可以在建立fail时将一些不存在的儿子指针指向对应的位置。
2、判断环时不要想当然地写个这样的版本:
bool dfs( int u ) { if( vis[u] ) return true; vis[u] = true; for( int t=0; t<g[u].size(); t++ ) { int v=g[u][t]; if( dfs(v) ) return true; } vis[u] = false; return false; }
它不是O(n)的,然后我就T了,搞了好久才弄好。
3、存在一个无限长的不与给定pattern匹配的text,那么在该text上跑ac自动机会无限循环,反之一定会在有限的时间内结束。
1 /************************************************************** 2 Problem: 2938 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:40 ms 7 Memory:2316 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <cstring> 12 #include <cstdlib> 13 #include <queue> 14 #define maxn 60010 15 using namespace std; 16 17 int son[maxn][2], fail[maxn], ikey[maxn], ntot; 18 int vis[maxn], cir[maxn]; 19 char str[maxn]; 20 21 void insert( const char *P ) { 22 int n=strlen(P); 23 int u=0; 24 for( int i=0; i<n; i++ ) { 25 int c=P[i]-'0'; 26 if( !son[u][c] ) son[u][c] = ++ntot; 27 u=son[u][c]; 28 } 29 ikey[u] = true; 30 } 31 void build_fail() { 32 queue<int> qu; 33 for( int c=0; c<2; c++ ) { 34 int v=son[0][c]; 35 if( !v ) continue; 36 qu.push( v ); 37 fail[v] = 0; 38 } 39 while( !qu.empty() ) { 40 int u=qu.front(); 41 qu.pop(); 42 for( int c=0; c<2; c++ ) { 43 int v=son[u][c]; 44 int w=fail[u]; 45 if( !v ) { 46 son[u][c] = son[fail[u]][c]; 47 continue; 48 } 49 while( w && !son[w][c] ) w=fail[w]; 50 fail[v] = son[w][c]; 51 ikey[v] |= ikey[fail[v]]; 52 qu.push( v ); 53 } 54 } 55 } 56 void dfs( int u ) { 57 vis[u] = true; 58 for( int c=0; c<2; c++ ) { 59 int v=son[u][c]; 60 if( cir[v] || ikey[v] ) continue; 61 if( !vis[v] ) 62 dfs(v); 63 else { 64 printf( "TAK\n" ); 65 exit(0); 66 } 67 } 68 cir[u] = true; 69 } 70 int main() { 71 int n; 72 scanf( "%d", &n ); 73 for( int i=0; i<n; i++ ) { 74 scanf( "%s", str ); 75 insert( str ); 76 } 77 build_fail(); 78 dfs( 0 ); 79 printf( "NIE\n" ); 80 }