题解 GRE Words Revenge
题目大意
给出 \(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的更多相关文章
- HDU4787 GRE Words Revenge【AC自动机 分块】
HDU4787 GRE Words Revenge 题意: \(N\)次操作,每次记录一个\(01\)串或者查询一个\(01\)串能匹配多少个记录的串,强制在线 题解: 在线的AC自动机,利用分块来降 ...
- GRE Words Revenge AC自动机 二进制分组
GRE Words Revenge 题意和思路都和上一篇差不多. 有一个区别就是需要移动字符串.关于这个字符串,可以用3次reverse来转换, 前面部分翻转一下, 后面部分翻转一下, 最后整个串翻转 ...
- ●HDU 4787 GRE Words Revenge
题链: http://acm.hdu.edu.cn/showproblem.php?pid=4787 题解: AC自动机(强制在线构造) 题目大意: 有两种操作, 一种为:+S,表示增加模式串S, 另 ...
- HDU 4787 GRE Words Revenge
Description Now Coach Pang is preparing for the Graduate Record Examinations as George did in 2011. ...
- HDU4787 GRE Words Revenge(AC自动机 分块 合并)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=4787 Description Now Coach Pang is preparing for ...
- [HDU 4787] GRE Words Revenge (AC自动机)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4787 题目大意: 给你若干个单词,查询一篇文章里出现的单词数.. 就是被我水过去的...暴力重建AC自 ...
- HDU-4787 GRE Words Revenge 解题报告
这是我之前博客里提到的一道AC自动机的练手题,但是要完成这道题,我之前博客里提到的东西还不够,这里总结一下这道题. 这道题不是一般的裸的AC自动机,它的询问和插入是交叉出现的所以用我之前写的板子不大合 ...
- [HDU4787]GRE Words Revenge 解题报告
这是我之前博客里提到的一道AC自动机的练手题,但是要完成这道题,我之前博客里提到的东西还不够,这里总结一下这道题. 这道题不是一般的裸的AC自动机,它的询问和插入是交叉出现的所以用我之前写的板子不大合 ...
- 题解 [CF332C] Students' Revenge
题面 解析 辣鸡题面毁我青春 因为翻译的题面中写了一句\(剩下的n−k个不会完成\). 所以就以为剩下的\(n-k\)个都会算上不满意值. (然而事实是只有\(p-k\)个...) 首先根据主席的规则 ...
随机推荐
- C++小坑汇总
std::vector::end, 是构想的下一个push_back位置,并不实际指向vector中任何元素. Returns an iterator referring to the past-th ...
- 详细分析MySQL事务日志(undo log)
2.undo log 2.1 基本概念 undo log有两个作用:提供回滚和多个行版本控制(MVCC). 在数据修改的时候,不仅记录了redo,还记录了相对应的undo,如果因为某些原因导致事务失败 ...
- CSP 2021 游记
\(\text{Day -INF}\) 看见了 \(\text{SCP2021}\) 的报名通知,想着应该教练会让我们统一报名,就没放在心上 然后-- 然后过了二十多天教练根本没有提报名的事情,搞得我 ...
- Gitlab(2)- centos7.x 下安装社区版 Gitlab 以及它的配置管理
前置准备:虚拟机安装以及配置相关 包含安装 centos7.8 虚拟机.设置静态 ip 等 https://www.cnblogs.com/poloyy/category/1703784.html 注 ...
- Vue设置全局cookies样式
''' 配置全局cookies样式 下载:cnpm install vue-cookies import cookies from 'vue-cookies' Vue.prototype.$cooki ...
- IDEA SpotBugs代码安全审计插件
IDEA SpotBugs代码安全审计插件 在寻找idea代码审计插件的时候,发现Findbugs已经停止更新,无法在idea2020.01版本运行,由此找到SpotBugs SpotBugs介绍 S ...
- json包中的Marshal&Unmarshal 文档译本
Marshal func Marshal(v interface{})([]byte, error) Marshal returns the JSON encoding of v. Marshal返回 ...
- Maven专题3——生命周期与插件
三套生命周期 Maven有3套相互独立的生命周期,用户可以调用某个生命周期的阶段,而不会对其他生命周期产生影响. 每个生命周期包含一些有先后顺序的阶段,后面的阶段依赖于前面的阶段,意味着用户调用后面的 ...
- 机器学习——softmax回归
softmax回归 前面介绍了线性回归模型适用于输出为连续值的情景.在另一类情景中,模型输出可以是一个像图像类别这样的离散值.对于这样的离散值预测问题,我们可以使用诸如 softmax 回归在内的分类 ...
- php 开启报错
// 开启报错提醒ini_set("display_errors", "On");error_reporting(E_ALL | E_STRICT); // 某 ...