题链:

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. fs检测文件夹状态

    var http = require("http"); var fs = require("fs"); var server = http.createServ ...

  2. 新手入门 git

    Git是目前世界上最先进的分布式版本控制系统 特点:高端大气上档次 什么是版本控制系统 系统自动记录文件改动 方便同事协作管理 不用自己管理一堆类似的文件了,也不需要把文件传来传去.如果想查看某次改动 ...

  3. java截取一个字符串正数或倒数某个特定字符前后的内容

    取出正数第二个“.”后面的内容 public class TestCode { public static void main(String[] args) { String str ="2 ...

  4. JAVA_SE基础——61.字符串入门

    public class Demo1 { public static void main(String[] args) { String str1 = "hello"; Strin ...

  5. Windows Powershell脚本执行

    在cmd下执行powershell进入shell模式: 变量定义:$i = 10 $a = ifconfig | findstr "192" Windows下的命令都可以执行如: ...

  6. vue.js+socket.io+express+mongodb打造在线聊天

    vue.js+socket.io+express+mongodb打造在线聊天 在线地址观看 http://www.chenleiming.com github地址 https://github.com ...

  7. SQL Server 实现递归查询

    基础数据/表结构                 Sql 语句 ;With cte(id,pid,TName)As ( Select id,pid,TName Union All Select B.i ...

  8. mosquitto验证client互相踢

    cleint11A订阅topic#################################################### server发送topic消息 ############### ...

  9. zuul入门(3)开发zuul的过滤器

    1.编写Zuul过滤器(Java&Groovy) 理解过滤器类型和请求生命周期后,我们来编写一个Zuul过滤器.编写Zuul的过滤器非常简单,我们只需继承抽象类ZuulFilter,然后实现几 ...

  10. Python学习之list有序集合

    # coding=utf-8 # list有序集合 classmate = ['Michael', 'Bob', 'Tracy'] print classmate print len(classmat ...