题目传送门

题目大意

给出 \(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. ASP截取字符 截取字符之间的字符

    ASP截取字符:MID函数Mid(变量或字串符,开始字节, 结尾字节(可不填)) InStrRev(变量, "字串符")  最后出现位置InStr(变量, "字串符&qu ...

  2. AbpVnext使用分布式IDistributedCache Redis缓存(自定义扩展方法)

    AbpVnext使用分布式IDistributedCache缓存from Redis(带自定义扩展方法) 我的依赖包的主要版本以及Redis依赖如下 1:添加依赖 <PackageReferen ...

  3. Linux常用命令(二)之权限管理、文件搜索、帮助、压缩命令及管道

    在(一)中提到过rwx的含义,但是我们还需深入理解,明白其真正的含义和权限,对于文件和目录,rwx权限是不同的,尤其是目录的权限往往是被忽略的: 对于目录,其权限和对应的操作: r-ls w-touc ...

  4. Android手机 自动批量发朋友圈

    做了各种对比之后,还是这个微商工具最好用

  5. QT之ARM平台的移植

      在开发板中运行QT程序的基本条件是具备QT环境,那么QT的移植尤为重要,接下载我将和小伙伴们一起学习QT的移植. 一.准备材料 tslib源码 qt-everywhere-src-5.12.9.t ...

  6. Robot Framework(6)- BuiltIn 测试库常用的关键字列表

    如果你还想从头学起Robot Framework,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1770899.html 前言 所有关键字 ...

  7. css对角渐变

    html: <div class="hh"> </div> css: .hh{ width: 500px; height: 500px; backgroun ...

  8. 面试官:MySQL的幻读是怎么被解决的?

    大家好,我是小林. 我之前写过一篇数据库事务的文章「 事务.事务隔离级别和MVCC」,这篇我说过什么是幻读. 在这里插入图片描述 然后前几天有位读者跟我说,我这个幻读例子不是已经被「可重复读」隔离级别 ...

  9. 274 day04_Map,斗地主案例

      day04 [Map] 主要内容 Map集合 教学目标 [ ] 能够说出Map集合特点 [ ] 使用Map集合添加方法保存数据 [ ] 使用"键找值"的方式遍历Map集合 [ ...

  10. 个人作业——CVPR顶会论文爬取

    main.py #保存单个界面数据 def getInfo(url): # url='https://openaccess.thecvf.com/WACV2021' header={ 'User-Ag ...