多校6 String(ac自动机)

题意:

给一本有\(n\)个单词的字典

\(q\)个查询 \(pref_i,suff_i\) 查询字典里有多少单词前缀匹配\(pref_i\),后缀同时匹配\(suff_i\),并且

\(pref_i\)和\(suf_i\)不相交

\(0 < n ,q <= 1e5\)

$ \sum (|pref_i| + |suff_i|) <= 5e5$

$ \sum |w_i| <= 5e5$

保证每组查询的前后缀不相交

思路:

forever97大神的这个思路很不错,比起题解的做法来说,更加符合字符串的套路吧

所有查询一起处理,把查询按$suff_i $ * $pref_i $,

中间用*隔开的形式拼接起来,丢到ac自动机里

然后对于字典里的每个单词 扩展成两倍,同样中间用 * 隔开,

在ac自动机里查询有多少个前后缀是该字符串的子串,比较一下长度就可以知道前后缀是否相交

这样就变成了最简单的在一个文本串中找哪些字符串出现过的问题了

#include<bits/stdc++.h>
#define LL long long
#define P pair<int,int>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ls rt<<1
#define rs (rt<<1|1)
using namespace std;
int read(){
int x = 0;
char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
return x;
}
const int SIZE = 27;
const int MAXNODE = 1e6 + 10;
const int N = 1e6 + 10;
char word[N],wo[N];
char pre[N],suf[N];
int w_len[N];
int pos[N];
int ans[N];
struct AC{
int ch[MAXNODE][SIZE];
int f[MAXNODE],last[MAXNODE],val[MAXNODE],length[MAXNODE];
int sz;
void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));length[0]=0;}
int idx(char c){return c - 'a';}
int _insert(char *s,int v){
int u = 0,len = strlen(s);
for(int i = 0;i < len;i++){
int c = idx(s[i]);
if(!ch[u][c]){
memset(ch[sz],0,sizeof ch[sz]);
val[sz] = 0;
length[sz] = i + 1;
ch[u][c] = sz++;
}
u = ch[u][c];
}
if(!val[u]) {ans[u] = 0,val[u] = v;}
return u;
}
void getFail(){
queue<int> q;
f[0] = 0;
for(int c = 0;c < SIZE;c++){
int u = ch[0][c];
if(u){
f[u] = 0;
q.push(u);
last[u] = 0;
}
}
while(!q.empty()){
int r = q.front();q.pop();
for(int c = 0;c < SIZE;c++){
int u = ch[r][c];
if(!u){ch[r][c] = ch[f[r]][c];continue;}
q.push(u);
int v = f[r];
while(v && !ch[v][c]) v = f[v];
f[u] = ch[v][c];
last[u] = val[f[u]]?f[u]:last[f[u]];
}
}
}
void cal(int len,int u){
if(u) {
if(length[u] <= len) ans[u]++;
cal(len,last[u]);
}
}
void Find(char *s,int l){
int len = strlen(s),u = 0;
for(int i = 0;i < len;i++){
u = ch[u][idx(s[i])];
if(val[u]) cal(l,u);
else if(last[u]) cal(l,last[u]);
}
}
}ac;
int main(){ int T,n,q;
T = read();
while(T--){
n = read(),q = read();
int total = 0;
for(int i = 1;i <= n;i++){
scanf("%s",wo);
w_len[i] = strlen(wo);
for(int j = 0;j < w_len[i];j++) word[j + total] = wo[j];
total += w_len[i];
}
ac.init();
for(int i = 1;i <= q;i++){
scanf("%s%s",pre,suf);
int l = strlen(pre),r = strlen(suf);
suf[r]='z'+1;
for(int j = 0;j < l;j++) suf[r+1+j] = pre[j];
suf[l + r + 1] = '\0';
pos[i] = ac._insert(suf,i);
};
ac.getFail();
int now = 0;
for(int i = 1;i <= n;i++) {
for(int j = 0;j < w_len[i];j++) pre[j + w_len[i] + 1] = pre[j] = word[now + j];
pre[w_len[i]] = 'z' + 1;
pre[2 * w_len[i] + 1] = '\0';
ac.Find(pre,w_len[i]+1);
now += w_len[i];
}
for(int i = 1;i <= q;i++) printf("%d\n",ans[pos[i]]);
}
return 0;
}

2017 多校6 String的更多相关文章

  1. 2017 多校5 Rikka with String

    2017 多校5 Rikka with String(ac自动机+dp) 题意: Yuta has \(n\) \(01\) strings \(s_i\), and he wants to know ...

  2. 2017 多校5 hdu 6093 Rikka with Number

    2017 多校5 Rikka with Number(数学 + 数位dp) 题意: 统计\([L,R]\)内 有多少数字 满足在某个\(d(d>=2)\)进制下是\(d\)的全排列的 \(1 & ...

  3. 2017 多校4 Wavel Sequence

    2017 多校4 Wavel Sequence 题意: Formally, he defines a sequence \(a_1,a_2,...,a_n\) as ''wavel'' if and ...

  4. 2017 多校4 Security Check

    2017 多校4 Security Check 题意: 有\(A_i\)和\(B_i\)两个长度为\(n\)的队列过安检,当\(|A_i-B_j|>K\)的时候, \(A_i和B_j\)是可以同 ...

  5. 2017 多校3 hdu 6061 RXD and functions

    2017 多校3 hdu 6061 RXD and functions(FFT) 题意: 给一个函数\(f(x)=\sum_{i=0}^{n}c_i \cdot x^{i}\) 求\(g(x) = f ...

  6. 2017 多校2 hdu 6053 TrickGCD

    2017 多校2 hdu 6053 TrickGCD 题目: You are given an array \(A\) , and Zhu wants to know there are how ma ...

  7. 2017 多校1 I Curse Myself

    2017 多校2 I Curse Myself(第k小生成树) 题目: 给一张带权无向连通图,该图的任意一条边最多只会经过一个简单环,定义\(V(k)为第k小生成树的权值和\),求出\(\sum_{k ...

  8. hdu6136[模拟+优先队列] 2017多校8

    有点麻烦.. /*hdu6136[模拟+优先队列] 2017多校8*/ #include <bits/stdc++.h> using namespace std; typedef long ...

  9. hdu6134[莫比乌斯反演] 2017多校8

    /*hdu6134[莫比乌斯反演] 2017多校8*/ #include <bits/stdc++.h> using namespace std; typedef long long LL ...

随机推荐

  1. js表格打印自动分页demo

    本文翻译自:How Does setState Know What to Do? 原作者:Dan Abramov 如果有任何版权问题,请联系shuirong1997@icloud.com 当你在组件中 ...

  2. php如何连接mysql,并操纵后台服务器运作的过程

    PHP,一个嵌套的缩写名称,是英文超级文本预处理语言(PHP:Hypertext Preprocessor)的缩写.PHP 是一种 HTML 内嵌式的语言,PHP与微软的ASP颇有几分相似,都是一种在 ...

  3. php 删除指定扩展名文件

    <?php /** *@param $path文件夹绝对路径 $file_type待删除文件的后缀名 *return void */ function clearn_file($path, $f ...

  4. python__高级 : @修饰器(装饰器)的理解

    以下是第一次了解的时候写的东西,有的地方理解不正确,虽已改正但是太片面,请直接看下面第二次修改加上的内容. ---------------------------------------------- ...

  5. python IDLE中如何执行for、while、if等多行语句

    >>> f=open("E:/pythonLearn/140.txt") >>> for line in f.readlines(): prin ...

  6. 笔记--tslib 编译

    tslib 是qt启动时的一个触屏校正检验程序. 它的配置以及编译比较简单. 第一步, 下载tslib源码包: http://download.csdn.net/detail/MKNDG/329156 ...

  7. python——直方图均衡化

    from PIL import Image from pylab import * from numpy import * def histeq(im,nbr_bins = 256): "& ...

  8. [Codeforces375D]Tree and Queries(莫队算法)

    题意:给定一棵树,每个节点有颜色,对于每个询问(u,k)询问以u为根节点的子树下有多少种颜色出现次数>=k 因为是子树,跟dfs序有关,转化为一段区间,可以用莫队算法求解 直接用一个数组统计出现 ...

  9. perl语言入门总结-第5章-输入输出

    读取标准输入 chomp($line = <STDIN>); #去掉后面的换行 while (defined($line = <STDIN>)) { print "I ...

  10. 笔记-python lib-pymongo

    笔记-python lib-pymongo 1.      开始 pymongo是python版的连接库,最新版为3.7.2. 文档地址:https://pypi.org/project/pymong ...