题目传送门

题目大意

给出 \(m\) 次操作,分别为以下两种操作:

  • 学习一个单词

  • 给出一个段落,查询里面有多少个学过的单词。注意,如果学习过 \(\text{ab,bc}\) ,当前查询段落为 \(\text{abc}\) ,那么应该算 \(2\) 个单词。

\(m\le 10^5\),保证学习的单词长度之和 \(\le 10^5\),给出的段落长度之和 \(\le 5\times 10^6\) 。

思路

据说可以直接拿暴力艹过去。。。(不会吧?阿sir?

可以看出来,如果只有一次查询,那其实就是一个裸的AC自动机,于是,问题就变成了如何维护一个动态的AC自动机。但是显然我们不可以,于是问题就是如何搞出一个伪在线AC自动机。

我们发现我们可以开两个AC自动机S1,S2,当S2里面的点数 \(\ge \sqrt n\) 的时候我们就直接把S1,S2进行暴力合并,否则暴力重构S2,就有点像根号分治。

然后我们通过分析发现我们的时间复杂度其实是 \(\Theta(n\sqrt n+m)\) 的,其中 \(n\) 是AC自动机里面的点数。

\(\texttt{Code}\)

#include <bits/stdc++.h>
using namespace std; #define Int register int
#define MAXN 5000005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} struct ACAM{
bool flag;//表示是否需要建立失配指针。
int tot,ch[MAXN][2],cnt[MAXN],fail[MAXN],last[MAXN];//fail表示失配指针,last表示上次有贡献的点,0是根,cnt表示是否是结束节点
void clear (){
for (Int i = 0;i <= tot;++ i) ch[i][0] = ch[i][1] = cnt[i] = 0;
tot = 0,flag =0;
}
void buildfail (){
queue <int> q;
for (Int i = 0;i < 2;++ i){
if (!ch[0][i]) continue;
q.push (ch[0][i]),fail[ch[0][i]] = last[ch[0][i]] = 0;
}
while (!q.empty()){
int u = q.front();q.pop ();
for (Int i = 0;i < 2;++ i){
int v = ch[u][i];
if (!v) continue;
int p = fail[u];while (p && !ch[p][i]) p = fail[p];
fail[v] = ch[p][i],last[v] = cnt[fail[v]] ? fail[v] : last[fail[v]];
q.push (v);
}
}
}
void insert (char *s){
flag = 1;int x = 0;
for (Int i = 0;s[i];++ i){
int now = s[i] - '0';
if (!ch[x][now]) ch[x][now] = ++ tot;
x = ch[x][now];
}
cnt[x] = 1;
}
int calc (int u){
int res = 0;
while (u){
res += cnt[u];
u = last[u];
}
return res;
}
int match (char *s){
if (flag) buildfail (),flag = 0;
int res = 0,x = 0;
for (Int i = 0;s[i];++ i){
int now = s[i] - '0';
while (x && !ch[x][now]) x = fail[x];
x = ch[x][now];
res += calc (x);
}
return res;
}
void Merge (ACAM &ot,int u,int v){
flag = 1;
for (Int i = 0;i < 2;++ i){
if (!ot.ch[v][i]) continue;
if (!ch[u][i]) ch[u][i] = ++ tot;
Merge (ot,ch[u][i],ot.ch[v][i]);
}
cnt[u] |= ot.cnt[v];
}
}SM[2]; char s[MAXN],t[MAXN]; void Solve (){
int n;read (n);
SM[0].clear(),SM[1].clear();
int lastans = 0,up = sqrt (MAXN);
while (n --> 0){
scanf ("%s",s);
int len = strlen (s + 1),shift = lastans % len;
t[len] = '\0';for (Int i = 0;i < len;++ i) t[i] = s[(i + shift) % len + 1];
if (s[0] == '?') write (lastans = SM[0].match (t) + SM[1].match (t)),putchar ('\n');
else{
SM[1].insert (t);
if (SM[1].tot > up) SM[0].Merge (SM[1],0,0),SM[1].clear();
}
}
} signed main(){
int t;read (t);
for (Int i = 1;i <= t;++ i) printf ("Case #%d:\n",i),Solve ();
return 0;
}

题解 GRE Words Revenge的更多相关文章

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

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

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

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

  3. ●HDU 4787 GRE Words Revenge

    题链: http://acm.hdu.edu.cn/showproblem.php?pid=4787 题解: AC自动机(强制在线构造) 题目大意: 有两种操作, 一种为:+S,表示增加模式串S, 另 ...

  4. HDU 4787 GRE Words Revenge

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

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

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

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

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

  7. HDU-4787 GRE Words Revenge 解题报告

    这是我之前博客里提到的一道AC自动机的练手题,但是要完成这道题,我之前博客里提到的东西还不够,这里总结一下这道题. 这道题不是一般的裸的AC自动机,它的询问和插入是交叉出现的所以用我之前写的板子不大合 ...

  8. [HDU4787]GRE Words Revenge 解题报告

    这是我之前博客里提到的一道AC自动机的练手题,但是要完成这道题,我之前博客里提到的东西还不够,这里总结一下这道题. 这道题不是一般的裸的AC自动机,它的询问和插入是交叉出现的所以用我之前写的板子不大合 ...

  9. 题解 [CF332C] Students' Revenge

    题面 解析 辣鸡题面毁我青春 因为翻译的题面中写了一句\(剩下的n−k个不会完成\). 所以就以为剩下的\(n-k\)个都会算上不满意值. (然而事实是只有\(p-k\)个...) 首先根据主席的规则 ...

随机推荐

  1. Faiss使用多线程出现的性能问题

    Faiss使用多线程出现的性能问题 faiss在增加CPU的情况下,反而出现效率低下的问题. 从理论上看,作为一个CPU/GPU计算型的应用,更多的核意味着更大的计算吞吐能力,性能只会越来越好才是. ...

  2. ES6——静态属性与静态方法

    静态方法只能写在class内,constructor外.通过static关键字声明 静态属性只能写在class外,通过 类名.属性名 = 属性值 声明 //静态属性与静态方法(ES6明确规定,Clas ...

  3. Metasploit用法详解

    Metasploit简介 1. Auxiliaries(辅助模块) 该模块不会直接在测试者和目标主机之间建立访问,它们只负责执行扫描.嗅探.指纹识别等相关功能以辅助渗透测试. 2. Exploit(漏 ...

  4. K8S资源编排(yaml)

    1.yaml的格式 2.yaml的组成部分 3.yaml常用字段的含义 4.yaml编写方式 (1)方式一:使用kubectl create命令生成yaml文件,然后修改 (2)方式2:在已经部署好的 ...

  5. Docker私有镜像仓库Harbor

    一.安装Harbor(离线安装包的方式安装) 1.解压离线包 2.进入harbor目录中编辑harbor.yml 3.安装docker-compose yum -y install docker-co ...

  6. Flask(6)- debug 模式

    使用 Flask 开发过程中存在两个常见的问题 当 Flask 程序出错时,没有提示错误的详细信息 修改 Flask 源代码后需要重启 Flask 程序 这两个问题非常的影响开发效率,因此 Flask ...

  7. .net中使用JSON

    在.NET使用JSON作为数据交换格式 ASP.NET中JSON的序列化和反序列化 三种方式: 使用System.Web.Script.Serialization.JavaScriptSerializ ...

  8. 放码来战!HMS Core线上Codelabs挑战赛正式开始

    亲爱的开发者,在1024程序员节即将到来之际,HMS Core准备了一场线上Codelabs挑战赛,现向你发出诚挚邀请,希望你能将新奇的想法和对产品的思考融入代码,用技术与世界对话. HMS Core ...

  9. -bash: ulimit: core file size: cannot modify limit: Operation not permitted

    一.问题描述 使用普通用户执行某个软件加载环境变量时报错 -bash: ulimit: core file size: cannot modify limit: Operation not permi ...

  10. gitlab安装CI问题汇总

    0.设置gitlab获取代码的存放位置 vim /etc/gitlab-runner/config.toml 1.unable to access http://gitlab-ci-token:xxx ...