解法看着吓人,其实就是为了优化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的更多相关文章

  1. CodeForces - 1207G :Indie Album(AC自动机 fail树上DFS)

    题意:有N个串,给出的形式是拼接给出,对于第i行:  (1,c)表示字符串i是单个字母c: (2,p,c)表示字符串i=在字符串p后面接上一个字母c. 然后给出M个提问,形式是(i,string).问 ...

  2. AC自动机fail树上dfs序建线段树+动态memset清空

    题意:http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路:https://blog.csdn.net/u013306830/article/detail ...

  3. 【BZOJ-3881】Divljak AC自动机fail树 + 树链剖分+ 树状数组 + DFS序

    3881: [Coci2015]Divljak Time Limit: 20 Sec  Memory Limit: 768 MBSubmit: 508  Solved: 158[Submit][Sta ...

  4. 洛谷2414(构建ac自动机fail树dfs序后遍历Trie树维护bit及询问答案)

    要点 这是一道蔡队题,看我标题行事 任意询问y串上有多少个x串,暴力找每个节点是不是结尾肯定是炸的,考虑本质:如果某节点是x的结尾,根据ac自动机的性质,x一定是此(子)串后缀.又有每个Trie节点的 ...

  5. AC自动机 & Fail树 专题练习

    Fail树就是AC自动机建出来的Fail指针构成的树. [bzoj3172][xsy1713]单词 题意 给定一些单词,求每个单词在所有单词里面的出现次数. 分析 构建Fail树,记录每个单词最后一个 ...

  6. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  7. 【bzoj2434-阿狸的打字机】AC自动机+fail树+优化

    http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=23083 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一 ...

  8. CF 163E. e-Government ac自动机+fail树+树状数组

    E. e-Government 题目: 给出n个字符串,表示n个人名,有两种操作: ?string ,统计字符串string中出现的属于城市居民的次数. +id,把编号为id的人变为城市居民,如果已经 ...

  9. 【学习笔记】ac自动机&fail树

    定义 解决文本串和多个模式串匹配的问题: 本质是由多个模式串形成的一个字典树,由tie的意义知道:trie上的每一个节点都是一个模式串的前缀: 在trie上加入fail边,一个节点fail边指向这个节 ...

随机推荐

  1. Druid数据源配置入门

    Druid是什么 Druid首先是一个数据库连接池.Druid是目前最好的数据库连接池,在功能.性能.扩展性方面,都超过其他数据库连接池,包括DBCP.C3P0.BoneCP.Proxool.JBos ...

  2. 团队冲刺DAY3

    DESUtil.java是包含加密解密抽象类的Java文件 DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准 ...

  3. JQ-jQuery-Ajax:jQuery Ajax 操作函数

    ylbtech-JQ-jQuery-Ajax:jQuery Ajax 操作函数 1.返回顶部 1. jQuery Ajax 操作函数 jQuery 库拥有完整的 Ajax 兼容套件.其中的函数和方法允 ...

  4. Java中深度克隆和浅度克隆

    一:使用目的: 就是为了快速构造一个和已有对象相同的副本.如果需要克隆对象,一般需要先创建一个对象,然后将原对象中的数据导入到新创建的对象中去,而不用根据已有对象进行手动赋值操作. 二:Object中 ...

  5. JavaScript实现10大算法可视化

    参考博客: https://www.cnblogs.com/Unknw/p/6346681.html#4195503 十大经典算法 一张图概括: 名词解释: n:数据规模 k:“桶”的个数 In-pl ...

  6. PHP CURL 模拟form表单上传遇到的小坑

    1:引用的时候 $parans ['img']=new \CURLFile($param); 传入的文件 在PHP版本5.5以上记得new CURLFile 不然会上传不成功 /** * http p ...

  7. leetcode.矩阵.240搜索二维矩阵II-Java

    1. 具体题目 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target.该矩阵具有以下特性:每行的元素从左到右升序排列:每列的元素从上到下升序排列. 示例: 现有矩阵 ...

  8. Error (10170): Verilog HDL syntax error at passwd.v(21) near text "if"; expecting an identifier ("if" is a reserved keyword ), or "endmodule", or a parallel statement

    你得加上时序啊笨蛋

  9. bzoj 3517翻硬币

    我们lv老师有点毒瘤啊... n为偶数... 离AC只差一张草稿纸233 挖个坑...

  10. JavaScript翻转字符串方法

    先把字符串转化成数组String.prototype.split(),再借助数组的reverse方法翻转数组顺序(Array.prototype.reverse()),然后把数组转化成字符串. 使用的 ...