●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 ...
随机推荐
- C语言博客作业--字符数组
一.PTA实验作业 题目1:统计一行文本的单词个数 1. 本题PTA提交列表 2. 设计思路 Begin 定义字符型变量ch,pre=' ': 定义整型变量count://用来记录单词个数 count ...
- 201621123057 《Java程序设计》第2周学习总结
一.本周学习总结 基本数据类型 char实质属于整型.boolean类型取值只有true和false两种. 引用数据类型 包装类:自动装箱 与 自动拆箱 数组:一维数组遍历数组用foreach循环:多 ...
- css3 文字的设置
1.text-shadow 有3个length参数,第1个表示水平偏移,第2个表示垂直偏移,第3个表示模糊(可选) .text11{text-shadow: 3px 3px 5px #f00 ;col ...
- R语言基础2
----------------------------------R语言学习与科研应用,科研作图,数据统计挖掘分析,群:719954246-------------------------- 通常, ...
- C# if判断语句执行顺序
DataTable dt = null; )//不报错,因为先执行dt != null 成立时才执行dt.Rows.Count > 0 { } && dt != null)//报 ...
- DDD实战进阶第一波(二):开发一般业务的大健康行业直销系统(搭建支持DDD的轻量级框架一)
要实现软件设计.软件开发在一个统一的思想.统一的节奏下进行,就应该有一个轻量级的框架对开发过程与代码编写做一定的约束. 虽然DDD是一个软件开发的方法,而不是具体的技术或框架,但拥有一个轻量级的框架仍 ...
- http缓存浅谈
我们在访问百度首页的时候,会发现不管怎么刷新页面,静态资源基本都是返回 200(from cache): 随便点开一个静态资源是酱的: 哎哟有Response报头数据呢,看来服务器也正常返回了etag ...
- JMeter入门(01)概念和样例
一.概念 JMeter 是一款专门用于功能测试和压力测试的轻量级测试开发平台,实现了许多和互联网相关的网络测试组件,同时还保留着很强的扩展性. JMeter可以用来测试诸如:静态文件,Java Ser ...
- OAuth2.0学习(1-2)OAuth2.0的一个企业级应用场景 - 新浪开放平台微博OAuth2.0认证
http://open.weibo.com/wiki/%E9%A6%96%E9%A1%B5 开发者可以先浏览OAuth2.0的接口文档,熟悉OAuth2.0的接口及参数的含义,然后我们根据应用场景各自 ...
- SpringBoot 概念和起步
一.概念和由来 1.什么是 Spring Boot Spring Boot 的设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用特定方式来进行配置,从而使开发人员不再需要定义样板化 ...