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
- hdu
- hdu
- HDU
- hdu ()
- hdu
- hdu
- HDU
- HDU
- hdu
- hdu
- HDU
- Hdu
- hdu
- hdu-
- hdu
- hdu
- hdu
- HDU
- 第十一周:( LeetCode474) Ones and Zeroes(c++)
- 文章标题
- 排序16:最短子数组
- 清除浮动方法
- PHP程序员的技术成长规划
- HDU
- C# MemoryStream类小结 (学习日记 2017-04-29)
- 虚函数中静态类型与动态类型
- 服务器开发过程中关于计时器的处理
- CentOS7之LVM实战
- UVA 11582 Colossal Fibonacci Numbers!
- 排序17:相邻两数最大差值
- 扑克牌顺子
- mysql与orcale实现递归查询