题链:

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. Beta版本展示

    Beta版本展示 开发团队:MyGod 团队成员:程环宇 张芷祎 王田路 张宇光 王婷婷 源码地址:https://github.com/WHUSE2017/MyGod MyGod团队项目的目标: 让 ...

  2. Node.js系列文章:编写自己的命令行界面程序(CLI)

    CLI的全称是Command-line Interface(命令行界面),即在命令行接受用户的键盘输入并作出响应和执行的程序. 在Node.js中,全局安装的包一般都具有命令行界面的功能,例如我们用于 ...

  3. Ubuntu安装使用latex

    TeX Live is a TeX distribution to get up and running with the TeX document production system. To ins ...

  4. Spring+Hibernate+Struts(SSH)框架整合

    SSH框架整合 前言:有人说,现在还是流行主流框架,SSM都出来很久了,更不要说SSH.我不以为然.现在许多公司所用的老项目还是ssh,如果改成流行框架,需要成本.比如金融IT这一块,数据库dao层还 ...

  5. 进军ABP第一天:ABP理论知识

    1.2.3 领域层领域层就是业务层,是一个项目的核心,所有业务规则都应该在领域层实现. ( 实体(Entity ) 实体代表业务领域的数据和操作,在实践中,通过用来映射成数据库表. ( 仓储(Repo ...

  6. LeetCode & Q1-Two Sum-Easy

    Array Hash Table Question Given an array of integers, return indices of the two numbers such that th ...

  7. Java KeyTool command

    Create a new key: keytool -genkey -alias keyAlias -keyalg RSA  -validity 1000 -keystore d:\keyPath\k ...

  8. URL编码和Base64编码 (转)

    我们经常会遇到所谓的URL编码(也叫百分号编码)和Base64编码.      先说一下Bsae64编码.BASE64编码是一种常用的将二进制数据转换为64个可打印字符的编码,常用于在通常处理文本数据 ...

  9. MySQL 避免重复数据的批量插入与批量更新

    [转发] 导读 我们在向数据库里批量插入数据的时候,会遇到要将原有主键或者unique索引所在记录更新的情况,而如果没有主键或者unique索引冲突的时候,直接执行插入操作. 这种情况下,有三种方式执 ...

  10. Linux CentOS7.0 (01)在Vmvare Workstation上 安装配置

    一.新建虚拟机 1.创建新的虚拟机 -> 默认典型 ->选择安装介质 2.指定虚拟机名称.安装目录.磁盘容量大小 点击 "完成",创建虚拟机! 随后虚拟机将自动启动安装 ...