题链:

http://acm.hdu.edu.cn/showproblem.php?pid=4787

题解:

AC自动机(强制在线构造)
题目大意:
有两种操作,
一种为:+S,表示增加模式串S,
另一种为:?S,表示查询S中有多少子串为已经给出的模式串。
(同时由于输入根据上一次的答案加密 ,所以强制在线)
(事先提一下,对于多次给出的相同模式串,是要去重的,至于怎么去重,就随便用trie树或者map+string就好了。)

进入正题:
难道真的要让AC自动机变得在线起来么?
其实还是用普通AC自动机做的。
即每次插入一个新的串,我们都重构AC自动机。
当然,为了保证时间复杂度,我们采取用两个AC自动机的做法:
不妨把两个AC自动机分别叫做A和B。
每次对于新来的模式串,我们把它加入B,并重构B自动机。
但B这个自动机有一个大小限制M,
一旦B的节点大小大于了M,我们就把B自动机的串全部放到A里面去,并清空B自动机。
然后对于每个询问,我们只需要在A,B里都分别求得答案并相加即可。

而至于复杂度,就是由B自动机的那个节点数目限制M决定的。
而M的取值为sqrt(模式串总长)时,复杂度就比较好了。
不妨假设所有模式串长度为len,全部插入trie树后节点也有len个。
由于每个新来的模式串都会重构B,而B的大小为sqrt(len),即重构代价为O(sqrt(len))
所以在B上花费的总复杂度为:O(串的个数n*sqrt(len))
由于每当B的大小为sqrt(len)时,就会把里面的串放入A,并重构A。
而A的大小最大就是len,上述的"把B里面的串放入A"的操作最多只会进行len/sqrt(len)=sqrt(len)次。
所以在A上花费的总复杂度为:O(len*sqrt(len))
所以实现这个在线构造AC自动机的复杂度为O(len*sqrt(len)+串的个数n*sqrt(len))

但是由于往往模式串的个数n不是很多,所以我们定义的M可以比sqrt(len)大一些,从而减小时间消耗 。

代码:

#include<bits/stdc++.h>
#define MAXN 100005
#define BSIZE 2000//320
#define rint register int
using namespace std;
int Case,N;
map<string,int>H;
string Str;
struct ACAM{
int size;
bool tag[MAXN];
int ch[MAXN][2],fail[MAXN],sum[MAXN];
void Reset(){
for(rint i=1;i<=size;i++)
tag[i]=ch[i][0]=ch[i][1]=0;
size=1;
}
int Insert(int p,int c){
if(!ch[p][c]) ch[p][c]=++size;
return ch[p][c];
}
void Getfail(){
static queue<int> Q;
Q.push(1); fail[1]=0;
while(!Q.empty()){
int u=Q.front(); Q.pop();
tag[u]|=tag[fail[u]];
for(int c=0;c<=1;c++){
int p=fail[u];
while(p&&!ch[p][c]) p=fail[p];
if(!ch[u][c]) ch[u][c]=p?ch[p][c]:1;
else{
int v=ch[u][c];
fail[v]=p?ch[p][c]:1; Q.push(v);
sum[v]=tag[v]+sum[fail[v]];
}
}
}
}
void Build(char *S){
Reset(); int p=1;
for(rint i=0;S[i];i++){
if(S[i]=='+'){
if(i!=0&&S[i-1]!='+') tag[p]=1; p=1;
}
else p=Insert(p,S[i]-'0');
}
tag[p]=1;
Getfail();
}
int Match(char *T){
static int p,ret,q; p=1; ret=0;
if(size==1) return ret;
for(rint i=0;T[i];i++){
if(T[i]=='?') p=1;
else p=ch[p][T[i]-'0'];
ret+=sum[p];
}
return ret;
}
}A,B;
char S[MAXN*52];
void decode(int br,int key,char *T){
static int len,p; len=strlen(T); //key=0;
for(int i=0,p=key%len;i<len;i++){
S[br+i]=T[p]; p++; if(p>=len) p-=len;
}
S[br+len]=0;
}
int main(){
static char T[MAXN*52];
scanf("%d",&Case);
int ar,br,newlen,ans=0;
for(int C=1;C<=Case;C++){
H.clear();
printf("Case #%d:\n",C);
scanf("%d",&N); ans=ar=br=0;
A.Reset(); B.Reset();
for(int i=1;i<=N;i++){
scanf(" %c",&S[br]); S[++br]=0;
scanf("%s",&T[0]);
decode(br,ans,T);
br--;
if(S[br]=='?'){
ans=0;
ans+=A.Match(&S[br]);
ans+=B.Match(&S[br]);
printf("%d\n",ans);
}
else{
Str=&S[br];
if(H[Str]==1) continue;
H[Str]=1;
newlen=strlen(&S[br]);
br+=newlen;
if(B.size>=BSIZE){
A.Build(&S[0]);
B.Reset(); ar=br;
}
else B.Build(&S[ar]);
}
}
}
return 0;
}

  

●HDU 4787 GRE Words Revenge的更多相关文章

  1. [HDU 4787] GRE Words Revenge (AC自动机)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4787 题目大意: 给你若干个单词,查询一篇文章里出现的单词数.. 就是被我水过去的...暴力重建AC自 ...

  2. HDU 4787 GRE Words Revenge

    Description Now Coach Pang is preparing for the Graduate Record Examinations as George did in 2011. ...

  3. 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 ...

  4. GRE Words Revenge AC自动机 二进制分组

    GRE Words Revenge 题意和思路都和上一篇差不多. 有一个区别就是需要移动字符串.关于这个字符串,可以用3次reverse来转换, 前面部分翻转一下, 后面部分翻转一下, 最后整个串翻转 ...

  5. HDU4787 GRE Words Revenge【AC自动机 分块】

    HDU4787 GRE Words Revenge 题意: \(N\)次操作,每次记录一个\(01\)串或者查询一个\(01\)串能匹配多少个记录的串,强制在线 题解: 在线的AC自动机,利用分块来降 ...

  6. HDU4787 GRE Words Revenge(AC自动机 分块 合并)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4787 Description Now Coach Pang is preparing for ...

  7. 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 ...

  8. HDU 5922 Minimum’s Revenge 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)

    Minimum's Revenge Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others ...

  9. HDU P3341 Lost's revenge 题解+数据生成器

    Lost and AekdyCoin are friends. They always play "number game"(A boring game based on numb ...

随机推荐

  1. 《招一个靠谱的移动开发》iOS面试题及详解(上篇)

    以下问题主要用于技术的总结与回顾 主要问题总结 单例的写法.在单利中创建数组应该注意些什么. NSString 的时候用copy和strong的区别. 多线程.特别是NSOperation 和 GCD ...

  2. bzoj千题计划220:bzoj3938: Robot

    http://www.lydsy.com/JudgeOnline/problem.php?id=3938 以时间为x轴,以距离为y轴,那么每个机器人的行走路径就是一条折线 把折线分段加入线段树里,然后 ...

  3. nyoj 矩形个数

    矩形的个数 时间限制:1000 ms  |  内存限制:65535 KB 难度:1   描述 在一个3*2的矩形中,可以找到6个1*1的矩形,4个2*1的矩形3个1*2的矩形,2个2*2的矩形,2个3 ...

  4. vue mint-ui 三级地址联动

    我也是第一次写这种地址联动的 刚开始的时候 我还以为直接用select来写 后来公司的ios告知并不是这样的 他说应该时这样的 于是第一想法 赶紧找插件吧 但是找了一会未果  就问了公司大神 他刚开始 ...

  5. 关于python爬虫经常要用到的一些Re.正则表达式

    转载:https://blog.csdn.net/skyeyesxy/article/details/50837984 1.正则表达式的常用符号与方法 常用符号:点号,星号,问号与括号(小括号) (. ...

  6. Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇——多页面VueSSR+热更新Server)

    Vue 2.x + Webpack 3.x + Nodejs 多页面项目框架(下篇--多页面VueSSR+热更新Server) @(HTML/JS) 这是Vue多页面框架系列文章的第二篇,上一篇(纯前 ...

  7. 操作MP3文件的元数据

    参见:http://jingyan.baidu.com/article/03b2f78c4d5eae5ea237aee7.html 一.MP3文件的元数据 一个规则的MP3文件大致含有3个部分: TA ...

  8. eclipse+Maven插件报错:-Dmaven.multiModuleProjectDirectory system propery is not set. Check $M2_HOME environment variable and mvn script match.

    问题描述: eclipse indigo+maven3.3.3+jdk1.70 maven插件执行报错:-Dmaven.multiModuleProjectDirectory system prope ...

  9. leetcode算法:Distribute Candies

    Given an integer array with even length, where different numbers in this array represent different k ...

  10. 高级控件之Scrollview ( 滑动屏幕 ) 与 Imageview (滑动屏幕 切换图片)

    ScrollView  的xml布局 <?xml version="1.0" encoding="utf-8"?> <RelativeLayo ...