多校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. HJ浇花

    题目描述 HJ养了很多花(99999999999999999999999999999999999盆),并且喜欢把它们排成一排,编号0~999999999999999999999999999999999 ...

  2. GUI测试问题汇总

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

  3. 屏蔽datatable错误提示

    $.fn.dataTable.ext.errMode = 'none'; //不显示任何错误信息// 以下为发生错误时的事件处理,如不处理,可不管.$('#productionRequestItems ...

  4. sql xml扩展字段 查询语句

    [cms:sql query="SELECT ContentXML.value('/fields[1]/Address[1]','varchar(max)')AS valueForm FRO ...

  5. perl语言入门总结-第3章-列表与数组

    1-列表list指的是标题的有序集合, 而数组(array)则是存储列表的变量. 更精确地说,列表指的是数据,而数组指的是变量. 访问数组中的元素 ] = "yabba"; ] = ...

  6. Hive数据导入导出的n种方式

    Tutorial-LoadingData Hive加载数据的6种方式 #格式 load data [local] inpath '/op/datas/xxx.txt' [overwrite] into ...

  7. 自定义注解不能拦截controller层

    1,首先在springMVC的配置文件中,webapp/WEB-INF/servlet.xml,加上AOP的相关内容: <beans xmlns="http://www.springf ...

  8. HTML中body相关标签-02

    今日内容: 字体标签: h1~h6.<font>.<u>.<b>.<strong><em>.<sup>.<sub> ...

  9. Hihocoder 1275 扫地机器人 计算几何

    题意: 有一个房间的形状是多边形,而且每条边都平行于坐标轴,按顺时针给出多边形的顶点坐标 还有一个正方形的扫地机器人,机器人只可以上下左右移动,不可以旋转 问机器人移动的区域能不能覆盖整个房间 分析: ...

  10. android systemtrace 报错

    折腾了很久,妈的,终于可以跑出来systemtrace了.如果你跟我一样,老是生成trace失败,那么,按我说的啦: 坑就在,你必须选一个路径存放trace.html,你不选一个,他就生成不了. 打开 ...