HDU

来源:互联网 发布:人工智能导论教学大纲 编辑:程序博客网 时间:2024/05/29 20:01

转载自:http://blog.csdn.net/no__stop/article/details/16823479 

题意:学习英语单词,有n个操作,每次可以读入一个单词,或者询问一个文本串,查询有多少个不同的单词已读入。文本是被加密过的,加密的方法就是将文本旋转上一次询问的答案次。旋转的操作不解释了,看下题目吧。

解题:AC自动机。大致的思路是用两个自动机,一个heap,一个buf,buf限制一个容量,buf插满了之后,再把buf合并到heap上。那么怎么达到在线呢?其实就是重建自动机。对于buf,因为容量上限是有阈值的,所以重建一次buf,复杂度是这个阈值的大小,而我们插入的次数最多只有L次,因此这个总复杂度是L*sqrt(L)的。而合并,其实也是暴力合并,把buf里的节点一个一个的往heap里面插,然后重建heap,每次合并操作的复杂度是heap的大小,但是我们只有在buf的大小超过阈值才会合并,因此总的最多只会合并sqrt(L)次。那么这里总的复杂度是L*sqrt (L)的。再就是询问,询问就把读进来的串在heap和buf上各跑一遍,然后和加起来就好了。当然了,这些只是大致的思路,具体细节还是有点麻烦的。

代码:

////自动机的合并在DFS上

#pragma comment( linker, "/STACK:1024000000,1024000000")  #include<stdio.h>  #include<string.h>  #include<algorithm>  #include<queue>  #include<math.h>  #define ll __int64  using namespace std ;    const int maxn = 511111 ;    struct AC_auto {      int tot , c[2][maxn] , fail[maxn] , val[maxn] ;      int cnt[maxn] , tri[2][maxn] ;      queue<int> q ;      inline int new_node () {          int i ;          for ( i = 0 ; i < 2 ; i ++ )              c[i][tot] = tri[i][tot] = 0 ;          val[tot] = cnt[tot] = 0 ;          return tot ++ ;      }      void init () {          tot = 0 ;          new_node () ;      }      int search ( char *s ) {          int i , now = 0 ;          for ( i = 0 ; s[i] ; i ++ ) {              int k = s[i] - '0' ;              now = tri[k][now] ;              if ( !now ) return 0 ;          }          if ( cnt[now] ) return 1 ;          return 0 ;      }      void insert ( char *s ) {          int now = 0 , i , j ;          for ( ; *s ; s ++ ) {              int k = *s - '0' ;              if ( !tri[k][now] ) tri[k][now] = new_node () ;              now = tri[k][now] ;          }          cnt[now] = 1 ;      }      void get_fail () {          int u = 0 , e , i , j ;          for ( i = 0 ; i < tot ; i ++ ) fail[i] = 0 ;          for ( i = 0 ; i < 2 ; i ++ )              if ( tri[i][u] ) {                  q.push ( tri[i][u] ) ;                  c[i][u] = tri[i][u] ;                  val[c[i][u]] = cnt[c[i][u]] ;              }          while ( !q.empty () ) {              int u = q.front () ;              q.pop () ;              for ( i = 0 ; i < 2 ; i ++ ) {                  if ( tri[i][u] ) {                      c[i][u] = tri[i][u] ;                      e = c[i][u] ;                      j = fail[u] ;                      fail[e] = c[i][j] ;                      q.push ( e ) ;                      val[e] = val[fail[e]] + cnt[e] ;                  }                  else c[i][u] = c[i][fail[u]] ;              }            }      }      ll find ( char *s , int len ) {          int now = 0 ;          ll ans = 0 ;          int i ;          for ( i = 1 ; i <= len ; i ++ ) {              int k = s[i] - '0' ;              now = c[k][now] ;              ans += val[now] ;          }          return ans ;      }  } heap , buf ;    void init () {      heap.init () ;      buf.init () ;  }  void dfs ( int u1 , int u2 ) {      int i ;      for ( i = 0 ; i < 2 ; i ++ ) {          if ( buf.tri[i][u2] ) {              int e2 = buf.tri[i][u2] ;              if ( !heap.tri[i][u1] ) heap.tri[i][u1] = heap.new_node () ;              int e1 = heap.tri[i][u1] ;              heap.cnt[e1] |= buf.cnt[e2] ;              dfs ( e1 , e2 ) ;          }      }  }    void join () {      dfs ( 0 , 0 ) ;      buf.init () ;      heap.get_fail () ;  }    char s[7654321] ;  char s1[7654321] ;  int main () {      int cas , ca = 0 , i , j ;      scanf ( "%d" , &cas ) ;      while ( cas -- ) {          printf ( "Case #%d:\n" , ++ ca ) ;          int n ; ll last = 0 ;          init () ;          scanf ( "%d" , &n ) ;          while ( n -- ) {              scanf ( "%s" , s1 ) ;              int len = strlen ( s1 + 1 ) ;              s[0] = s1[0] ;              for ( i = 0 ; i < len ; i ++ ){                  s[i+1] = s1[1+(i+last%len+len)%len] ;              }              s[len+1] = 0 ;              if ( s[0] == '+' ) {                  i = buf.search ( s + 1 ) ;                  j = heap.search ( s + 1 ) ;                  if ( i || j ) continue ;                  buf.insert ( s + 1 ) ;                  buf.get_fail () ;                  if ( buf.tot > 2000 ) join () ;              }              else {                  last = buf.find ( s , len ) + heap.find ( s , len ) ;                  printf ( "%I64d\n" , last ) ;              }          }      }      return 0 ;  }  


0 0