●HDU 4787 GRE Words Revenge
题链:
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的更多相关文章
- [HDU 4787] GRE Words Revenge (AC自动机)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4787 题目大意: 给你若干个单词,查询一篇文章里出现的单词数.. 就是被我水过去的...暴力重建AC自 ...
- HDU 4787 GRE Words Revenge
Description Now Coach Pang is preparing for the Graduate Record Examinations as George did in 2011. ...
- 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 ...
- GRE Words Revenge AC自动机 二进制分组
GRE Words Revenge 题意和思路都和上一篇差不多. 有一个区别就是需要移动字符串.关于这个字符串,可以用3次reverse来转换, 前面部分翻转一下, 后面部分翻转一下, 最后整个串翻转 ...
- HDU4787 GRE Words Revenge【AC自动机 分块】
HDU4787 GRE Words Revenge 题意: \(N\)次操作,每次记录一个\(01\)串或者查询一个\(01\)串能匹配多少个记录的串,强制在线 题解: 在线的AC自动机,利用分块来降 ...
- HDU4787 GRE Words Revenge(AC自动机 分块 合并)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4787 Description Now Coach Pang is preparing for ...
- 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 5922 Minimum’s Revenge 【模拟】 (2016CCPC东北地区大学生程序设计竞赛)
Minimum's Revenge Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others ...
- HDU P3341 Lost's revenge 题解+数据生成器
Lost and AekdyCoin are friends. They always play "number game"(A boring game based on numb ...
随机推荐
- Beta版本展示
Beta版本展示 开发团队:MyGod 团队成员:程环宇 张芷祎 王田路 张宇光 王婷婷 源码地址:https://github.com/WHUSE2017/MyGod MyGod团队项目的目标: 让 ...
- Node.js系列文章:编写自己的命令行界面程序(CLI)
CLI的全称是Command-line Interface(命令行界面),即在命令行接受用户的键盘输入并作出响应和执行的程序. 在Node.js中,全局安装的包一般都具有命令行界面的功能,例如我们用于 ...
- Ubuntu安装使用latex
TeX Live is a TeX distribution to get up and running with the TeX document production system. To ins ...
- Spring+Hibernate+Struts(SSH)框架整合
SSH框架整合 前言:有人说,现在还是流行主流框架,SSM都出来很久了,更不要说SSH.我不以为然.现在许多公司所用的老项目还是ssh,如果改成流行框架,需要成本.比如金融IT这一块,数据库dao层还 ...
- 进军ABP第一天:ABP理论知识
1.2.3 领域层领域层就是业务层,是一个项目的核心,所有业务规则都应该在领域层实现. ( 实体(Entity ) 实体代表业务领域的数据和操作,在实践中,通过用来映射成数据库表. ( 仓储(Repo ...
- LeetCode & Q1-Two Sum-Easy
Array Hash Table Question Given an array of integers, return indices of the two numbers such that th ...
- Java KeyTool command
Create a new key: keytool -genkey -alias keyAlias -keyalg RSA -validity 1000 -keystore d:\keyPath\k ...
- URL编码和Base64编码 (转)
我们经常会遇到所谓的URL编码(也叫百分号编码)和Base64编码. 先说一下Bsae64编码.BASE64编码是一种常用的将二进制数据转换为64个可打印字符的编码,常用于在通常处理文本数据 ...
- MySQL 避免重复数据的批量插入与批量更新
[转发] 导读 我们在向数据库里批量插入数据的时候,会遇到要将原有主键或者unique索引所在记录更新的情况,而如果没有主键或者unique索引冲突的时候,直接执行插入操作. 这种情况下,有三种方式执 ...
- Linux CentOS7.0 (01)在Vmvare Workstation上 安装配置
一.新建虚拟机 1.创建新的虚拟机 -> 默认典型 ->选择安装介质 2.指定虚拟机名称.安装目录.磁盘容量大小 点击 "完成",创建虚拟机! 随后虚拟机将自动启动安装 ...