ac自动机fail树上按询问建立上跳指针——cf963D
解法看着吓人,其实就是为了优化ac自动机上暴力跳fail指针。。
另外这题对于复杂度的分析很有学习价值
/*
给定一个母串s,再给定n个询问(k,m)
对于每个询问,求出长度最小的t,使t是s的子串,且m作为子串在t中出现了m次 对多串建立ac自动机,然后用s去匹配,把所有询问的出现位置都用vector保存下来
然后对应每个询问的k进行更新答案 为了保证复杂度:在跳fail不能暴力向上跳,应该直接用一个指针pre跳到上一个带有询问的点
这样每次向上跳都让某个询问的vector更新进一个新的值
由于最多有sqrt(n)个不同的询问串长度,所以以每个s[i]为结尾的可匹配串也只有sqrt(n)个,
即最多在fail树上跳nsqrt(n)次
*/
#include<bits/stdc++.h>
using namespace std;
#define N 200005 struct Query{
vector<int>pos;
int k,len;
}q[N];
char s[N],buf[N];
int n; struct Trie{
int nxt[N][],fail[N],id[N],pre[N];
int root,L;
int newnode(){
memset(nxt[L],-,sizeof nxt[L]);
id[L]=;
return L++;
}
void init(){L=;root=newnode();}
void insert(char buf[],int ID){
int len=strlen(buf);
int now=root;
for(int i=;i<len;i++){
if(nxt[now][buf[i]-'a']==-)
nxt[now][buf[i]-'a']=newnode();
now=nxt[now][buf[i]-'a'];
}
id[now]=ID;
}
void build(){
queue<int>q;
fail[root]=root;
for(int i=;i<;i++)
if(nxt[root][i]==-)
nxt[root][i]=root;
else {
fail[nxt[root][i]]=root;
q.push(nxt[root][i]);
}
pre[root]=; while(q.size()){
int now=q.front();q.pop();//此时now的fail已经建立好
if(id[fail[now]]!=)//找上一个询问的位置
pre[now]=fail[now];
else
pre[now]=pre[fail[now]]; for(int i=;i<;i++)
if(nxt[now][i]==-)
nxt[now][i]=nxt[fail[now]][i];
else {
fail[nxt[now][i]]=nxt[fail[now]][i];
q.push(nxt[now][i]);
}
}
} void query(char *s){
int len=strlen(s);
int now=root;
for(int i=;i<len;i++){
now=nxt[now][s[i]-'a'];
//通过pre向上跳
int p=now;
while(p){
q[id[p]].pos.push_back(i);
p=pre[p];
}
} }
}ac; int main(){
ac.init();
scanf("%s",s);
cin>>n;
for(int i=;i<=n;i++){
scanf("%d%s",&q[i].k,buf);
q[i].len=strlen(buf);
ac.insert(buf,i);
}
ac.build();
ac.query(s); //for(int i=1;i<=ac.L;i++)
// cout<<ac.pre[i]<<" "; //处理每个询问
for(int i=;i<=n;i++){
//cout<<q[i].pos.size()<<"\n";
if(q[i].pos.size()<q[i].k){
puts("-1");continue;
} int ans=0x3f3f3f3f;
for(int j=q[i].k-;j<q[i].pos.size();j++){
ans=min(ans,q[i].pos[j]-q[i].pos[j-q[i].k+]+q[i].len);
}
cout<<ans<<'\n';
}
}
/* aaabbbbaaabababab
27
2 aaabbbbaaaba
2 baaabab
1 abbbbaaabab
1 aabbbbaaabab
6 a
1 aaabbbbaaabababab
2 aaba
2 abbbba
5 aa
2 aaabbbb
2 abababa
3 aba
2 baaa
2 bbaaababa
1 aaabab
1 abbb
1 bbbbaaabababa
1 baaab
1 abbbbaaabababa
1 aaababa
1 ababab
2 abb
2 baaabababa
1 bbaaabababa
2 aaabb
1 abababab
4 bab */
ac自动机fail树上按询问建立上跳指针——cf963D的更多相关文章
- CodeForces - 1207G :Indie Album(AC自动机 fail树上DFS)
题意:有N个串,给出的形式是拼接给出,对于第i行: (1,c)表示字符串i是单个字母c: (2,p,c)表示字符串i=在字符串p后面接上一个字母c. 然后给出M个提问,形式是(i,string).问 ...
- AC自动机fail树上dfs序建线段树+动态memset清空
题意:http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路:https://blog.csdn.net/u013306830/article/detail ...
- 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序
3881: [Coci2015]Divljak Time Limit: 20 Sec Memory Limit: 768 MBSubmit: 508 Solved: 158[Submit][Sta ...
- 洛谷2414(构建ac自动机fail树dfs序后遍历Trie树维护bit及询问答案)
要点 这是一道蔡队题,看我标题行事 任意询问y串上有多少个x串,暴力找每个节点是不是结尾肯定是炸的,考虑本质:如果某节点是x的结尾,根据ac自动机的性质,x一定是此(子)串后缀.又有每个Trie节点的 ...
- AC自动机 & Fail树 专题练习
Fail树就是AC自动机建出来的Fail指针构成的树. [bzoj3172][xsy1713]单词 题意 给定一些单词,求每个单词在所有单词里面的出现次数. 分析 构建Fail树,记录每个单词最后一个 ...
- BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)
题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...
- 【bzoj2434-阿狸的打字机】AC自动机+fail树+优化
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23083 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一 ...
- CF 163E. e-Government ac自动机+fail树+树状数组
E. e-Government 题目: 给出n个字符串,表示n个人名,有两种操作: ?string ,统计字符串string中出现的属于城市居民的次数. +id,把编号为id的人变为城市居民,如果已经 ...
- 【学习笔记】ac自动机&fail树
定义 解决文本串和多个模式串匹配的问题: 本质是由多个模式串形成的一个字典树,由tie的意义知道:trie上的每一个节点都是一个模式串的前缀: 在trie上加入fail边,一个节点fail边指向这个节 ...
随机推荐
- security 页面测试
<!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content=& ...
- configure: error: invalid variable name: `-prefix'
configure: error: invalid variable name: `-prefix'其实就是写法的问题 正确写法 把prefix前面的"-"改成“--”
- legend2---17、legend2里面怎么面向对象
legend2---17.legend2里面怎么面向对象 一.总结 一句话总结: mvc本身挺优:本身mvc的开发模式,就算是面向过程下也还行,如果面向对象那就更加棒了 实体类无需属性:由于php的生 ...
- NLayer Architecture in abp
https://aspnetboilerplate.com/Pages/Documents/NLayer-Architecture Introduction The layering of an ap ...
- 使用cookie来做身份认证 转载https://www.cnblogs.com/sheldon-lou/p/9545726.html
文章是msdn的官方文档,链接在这里.其实也有中文的文档,这里还是想做一个记录. 文章有asp.net core 2.x 和1.x 版本,我这里就忽略1.x了. 下面先说几点额外的东西有助于理解. A ...
- Leetcode 最长连续序列
题目链接:https://leetcode-cn.com/problems/longest-consecutive-sequence/ 题目大意: 略. 分析: 注意有重复值,序列为空等情况. 代码如 ...
- 慎用margin系列3---IE6下3px bug
当我们想让一段文字出现在一个布局块的右边的时候,我们会让布局块向左浮动,然后把段落设置左布局块宽度大小的左空白.比如左布局块是.a{float:left;height: 110px;width: 28 ...
- overflow:hidden失效
overflow:hidden失效 为了页面的健壮性,我们常常需要使用overflow:hidden.有时候是为了防止布局被撑开,有时候是为了配合其它规则实现文字截断,还有时候纯粹是为了创建块级上下文 ...
- python之chardet验证编码格式
在处理字符串时,常常会遇到不知道字符串是何种编码,如果不知道字符串的编码就不能将字符串转换成需要的编码 pip install chardet 举例子 import chardet import ur ...
- python之arrow时间处理模块
首先安装 pip install arrow 直接创建arrow对象 print(arrow.get(2019, 1, 23)) # 2019-01-23T00:00:00+00:00 print(a ...