HDU4787 GRE Words Revenge(AC自动机 分块 合并)
题目
Source
http://acm.hdu.edu.cn/showproblem.php?pid=4787
Description
Now Coach Pang is preparing for the Graduate Record Examinations as George did in 2011. At each day, Coach Pang can:
"+w": learn a word w
"?p": read a paragraph p, and count the number of learnt words. Formally speaking, count the number of substrings of p which is a learnt words.
Given the records of N days, help Coach Pang to find the count. For convenience, the characters occured in the words and paragraphs are only '0' and '1'.
Input
The first line of the input file contains an integer T, which denotes the number of test cases. T test cases follow.
The first line of each test case contains an integer N (1 <= N <= 105), which is the number of days. Each of the following N lines contains either "+w" or "?p". Both p and w are 01-string in this problem.
Note that the input file has been encrypted. For each string occured, let L be the result of last "?" operation. The string given to you has been shifted L times (the shifted version of string s1s2 ... sk is sks1s2 ... sk-1). You should decrypt the string to the original one before you process it. Note that L equals to 0 at the beginning of each test case.
The test data guarantees that for each test case, total length of the words does not exceed 105 and total length of the paragraphs does not exceed 5 * 106.
Output
For each test case, first output a line "Case #x:", where x is the case number (starting from 1).
And for each "?" operation, output a line containing the result.
Sample Input
2
3
+01
+01
?01001
3
+01
?010
?011
Sample Output
Case #1:
2
Case #2:
1
0
分析
题目大概说有依次进行N个操作,每个操作可以是学习一个单词,或者读一个段落并求出段落里有多少个子串是已经学习的单词。
建立两个AC自动机,一个大的,一个小的。每次更新插入到小的自动机并重构,小的自动机结点数有限制,一旦超过限制就将其合并到大的,然后大的重构,小的清空。。如此就OK了。。
这么做的时间复杂度——
- 不妨设小的自动机大小限制为$\sqrt L$,$L$为插入的模式串总长,于是最多插入$L$次,每次重构fail时间复杂度可以做到线性的即$O(\sqrt L)$,这样小的自动机这儿总时间复杂度是$O(L\sqrt L)$;
- 对于大的来说,最多的合并次数为$\frac L{\sqrt L}$即$\sqrt L$,每次合并时间复杂度$O(\sqrt L)$,每次重构$O(L)$,那么总的时间复杂度是$O(L\sqrt L)$。
- 而查询,就是在两个AC自动机上跑一遍主串即可,也是可以做到线性的,即$O(L+\sum |主串|)$。
有点神奇。。
代码
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
#define MAXN 100100 struct AC_auto{
int ch[MAXN][2],fail[MAXN],tn;
bool flag[MAXN];
void init(){
for(int i=0; i<=tn; ++i){
ch[i][0]=ch[i][1]=flag[i]=0;
}
tn=0;
}
void insert(char *s){
int x=0;
for(int i=0; s[i]; ++i){
int y=s[i]-'0';
if(ch[x][y]==0) ch[x][y]=++tn;
x=ch[x][y];
}
flag[x]=1;
}
void getfail(){
for(int i=0; i<=tn; ++i) fail[i]=0;
queue<int> que;
for(int i=0; i<2; ++i){
if(ch[0][i]) que.push(ch[0][i]);
}
while(!que.empty()){
int x=que.front(); que.pop();
for(int i=0; i<2; ++i){
if(ch[x][i]==0) continue;
que.push(ch[x][i]);
int tmp=fail[x];
while(tmp && ch[tmp][i]==0){
tmp=fail[tmp];
}
fail[ch[x][i]]=ch[tmp][i];
}
}
}
int match(char *s){
int x=0,ret=0;
for(int i=0; s[i]; ++i){
int y=s[i]-'0';
while(x && ch[x][y]==0) x=fail[x];
x=ch[x][y];
int tmp=x;
while(tmp){
if(flag[tmp]) ++ret;
tmp=fail[tmp];
}
}
return ret;
}
bool query(char *s){
int x=0;
for(int i=0; s[i]; ++i){
int y=s[i]-'0';
if(ch[x][y]==0) return 0;
x=ch[x][y];
}
return flag[x];
}
}ac,buf; void dfs(int u,int v){
for(int i=0; i<2; ++i){
if(buf.ch[v][i]==0) continue;
if(ac.ch[u][i]==0){
ac.ch[u][i]=++ac.tn;
ac.ch[ac.tn][0]=ac.ch[ac.tn][1]=0;
ac.flag[ac.tn]=0;
}
if(buf.flag[buf.ch[v][i]]) ac.flag[ac.ch[u][i]]=1;
dfs(ac.ch[u][i],buf.ch[v][i]);
}
}
void join(){
dfs(0,0);
buf.init();
ac.getfail();
} char str[5111111],s[5111111];
int main(){
int t;
scanf("%d",&t);
for(int cse=1; cse<=t; ++cse){
printf("Case #%d:\n",cse);
ac.init();
buf.init();
int n;
scanf("%d",&n);
int lastans=0;
char op;
while(n--){
scanf(" %c",&op);
scanf("%s",str);
int len=strlen(str);
for(int i=0; i<len; ++i){
s[i]=str[(i+lastans)%len];
}
s[len]=0;
if(op=='+'){
if(ac.query(s) || buf.query(s)) continue;
buf.insert(s);
buf.getfail();
if(buf.tn>2000) join();
}else{
lastans=ac.match(s)+buf.match(s);
printf("%d\n",lastans);
}
}
}
return 0;
}
HDU4787 GRE Words Revenge(AC自动机 分块 合并)的更多相关文章
- GRE Words Revenge AC自动机 二进制分组
GRE Words Revenge 题意和思路都和上一篇差不多. 有一个区别就是需要移动字符串.关于这个字符串,可以用3次reverse来转换, 前面部分翻转一下, 后面部分翻转一下, 最后整个串翻转 ...
- [HDU 4787] GRE Words Revenge (AC自动机)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4787 题目大意: 给你若干个单词,查询一篇文章里出现的单词数.. 就是被我水过去的...暴力重建AC自 ...
- HDU4787 GRE Words Revenge【AC自动机 分块】
HDU4787 GRE Words Revenge 题意: \(N\)次操作,每次记录一个\(01\)串或者查询一个\(01\)串能匹配多少个记录的串,强制在线 题解: 在线的AC自动机,利用分块来降 ...
- HDU 3341 Lost's revenge AC自动机+dp
Lost's revenge Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)T ...
- HDU-4787 GRE Words Revenge 解题报告
这是我之前博客里提到的一道AC自动机的练手题,但是要完成这道题,我之前博客里提到的东西还不够,这里总结一下这道题. 这道题不是一般的裸的AC自动机,它的询问和插入是交叉出现的所以用我之前写的板子不大合 ...
- 【CF587F】Duff is Mad AC自动机+分块
[CF587F]Duff is Mad 题意:给出n个串$s_1,s_2..s_n$,有q组询问,每次给出l,r,k,问你编号在[l,r]中的所有串在$s_k$中出现了多少次. $\sum|s_i|, ...
- [HDU4787]GRE Words Revenge 解题报告
这是我之前博客里提到的一道AC自动机的练手题,但是要完成这道题,我之前博客里提到的东西还不够,这里总结一下这道题. 这道题不是一般的裸的AC自动机,它的询问和插入是交叉出现的所以用我之前写的板子不大合 ...
- hdu 4117 GRE Words (ac自动机 线段树 dp)
参考:http://blog.csdn.net/no__stop/article/details/12287843 此题利用了ac自动机fail树的性质,fail指针建立为树,表示父节点是孩子节点的后 ...
- HDU3341 Lost's revenge(AC自动机&&dp)
一看到ACGT就会想起AC自动机上的dp,这种奇怪的联想可能是源于某道叫DNA什么的题的. 题意,给你很多个长度不大于10的小串,小串最多有50个,然后有一个长度<40的串,然后让你将这个这个长 ...
随机推荐
- H5案例分享:JS手势框架 —— Hammer.js
JS手势框架 -- Hammer.js 一.hammer.js简介 hammerJS是一个开源的,轻量级的触屏设备javascript手势库,它可以在不需要依赖其他东西的情况下识别触摸,鼠标事件.允许 ...
- 第二篇 基于.net搭建热插拔式web框架(沙箱的构建)
上周五写了一个实现原理篇,在评论中看到有朋友也遇到了我的问题,真的是有种他乡遇知己的感觉,整个系列我一定会坚持写完,并在最后把代码开源到git中.上一篇文章很多人看了以后,都表示不解,觉得不知道我到底 ...
- ORA-01033 ORACLE 正在初始化或关闭
(借鉴:该方法本人亲自操作过,解决了问题!) 解决连接ORACLE错误一例:ORA-01033: ORACLE 正在初始化或关闭 客户发现连接数据库有问题,错误有: ORA-01033: ORACLE ...
- c++中的继承与初始化
1.在c++中构造函数.析构函数.=运算符.友元无法继承 2.const 成员.引用成员.类的对象成员没有默认构造函数时,需在类的构造函数初始化列表中对其进行初始化 3.基类无默认构造函数,派生类需在 ...
- wget 断点续传 & nginx文件服务器
nginx默认支持断点续传: 测试方法: wget -S http://httpd.apache.org/images/httpd_logo_wide_new.png 2>&1 | gr ...
- 最新版 chrome 33中,backgroundPosition 改了.
ctrl.css('backgroundPosition' 返回值不一样, 原来是:-75px 0px 现在是:left 75px top 0px // chrome 33 返回的是 left 0px ...
- DevExpress 隐藏Ribbon中barbuttonItem的SuperTip(2)
在form界面增加 toolTipController 工具 然后将 ribbonControl.ToolTipController 的属性设置成 toolTipController toolTipC ...
- Spring MVC 中 HandlerInterceptorAdapter的使用
一般情况下,对来自浏览器的请求的拦截,是利用Filter实现的,这种方式可以实现Bean预处理.后处理. Spring MVC的拦截器不仅可实现Filter的所有功能,还可以更精确的控制拦截精度. s ...
- wget 扒站
在Linux下,通过一个命令就可以把整个站相关的文件全部下载下来. wget -r -p -k -np [网址] 参数说明: -r : 递归下载 -p : 下载所有用于显示 HTML 页面的图片之类的 ...
- android 决解启动屏白黑屏会延迟几秒的问题
通常写启动屏,都有个很不喜欢的问题,就是会空白几秒才显示界面,而且界面还是很简单的! 解决办法 1 写一个透明的主题,一般启动屏都是不要bar的所以继承AppTheme.NoActionBar < ...