多校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. SAP库存历史库存表更新逻辑 (转)

    根据库存类型的不同,库存信息保存在不同的表中,具体而言见下表 库存类型 当前库存 历史库存 库存金额 历史库存金额 工厂级别库存 MARC MARCH MBEW MBEWH MBEW 库存地点库存 M ...

  2. GUI测试问题汇总

    1.ajax实现的页面元素定位问题 最近在做项目的时候遇到一个问题,通过xpath定位到元素后做一个循环操作,第一循环可以正常执行,第二次循环后就报错,错误信息:Message: The elemen ...

  3. Java OOP——第八章 File IO

    1.文件:文件可认为是相关记录或放在一起的数据的集合: 2.File类:名命空间:java.io File对象即可表示文件,也可表示目录, 在程序中,一个File对象可以代表一个文件或目录, 利用他可 ...

  4. scrapy--json(喜马拉雅Fm)(二)

    学习了对数据的储存,感觉还不够深入,昨天开始对储存数据进行提取.整合和图像化显示.实例还是喜马拉雅Fm,算是对之前数据爬取之后的补充. 明确需要解决的问题 1,蕊希电台全部作品的进行储存 --scra ...

  5. HTML+CSS : H5+CSS3

    HTML5语义化标签: header nav(导航) article section(章节) aside(侧边栏) footer------------------------------------ ...

  6. php正则 与 js正则

    PHP中的正则表达式函数 在PHP中有两套正则表达式函数库.一套是由PCRE(Perl Compatible Regular Expression)库提供的.PCRE库使用和Perl相同的语法规则实现 ...

  7. Codeforces146D 概率DP

    Bag of mice The dragon and the princess are arguing about what to do on the New Year's Eve. The drag ...

  8. Codeforces Round #438 C - Qualification Rounds 思维

    C. Qualification Rounds time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  9. com.squareup.okhttp.Interceptor

    retrift 集成了okhttp,所以,我们以后就不用再单独的引用http的jar 了. 但是,今天遇到一个问题,就是okhttp是这样设置一些intercept的: private static ...

  10. http客户端缓存

    这篇文章写得比较,点击查看