多校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. BFS练习-POJ.2386

    Lake Counting Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 35122 Accepted: 17437 Descr ...

  2. 谈谈两种标准库类型---string和vector

    两种最重要的标准库---string和vector string和vector是两种最重要的标准库类型,string表示可变长的字符序列,vector存放的是某种给定类型对象的可变长序列. 一.标准库 ...

  3. Python线程创建与使用

    Python多为线程编程提供了两个简单明了的模块:thread和threading,Python3中已经不存thread模块,已经被改名为_thread,实际优先使用 threading模块. 1.P ...

  4. 利用sysbench进行MySQL OLTP基准测试

      Preface       In order to know clearly about the real performance threshold of database server,we ...

  5. Centos下使用Docker部署MySql

    本文讲述 CentOS 系统 Docker 中安装 MySql 的过程 步骤 1. 拉取 Docker Hub 官方提供的mysql镜像 docker pull mysql:5.7 2.运行容器 do ...

  6. Go HTTP模块处理流程简析

    Go语言提供完善的net/http包,用户使用起来非常方便简单,只需几行代码就可以搭建一个简易的Web服务,可以对Web路由.静态文件.cookie等数据进行操作. 一个使用http包建立的Web服务 ...

  7. JAVA / MySql 编程—— 第一章 数据库的设计

     1.        数据库设计:将数据库中的数据实体及这些数据实体之间的关系进行规划和结构化的过程: 良好的数据库设计: 节省数据的存储空间 能够保证数据的完整性 方便进行数据库应用系统的开发 糟糕 ...

  8. git push 时 fatal: Unable to create 'D:/phpStudy/WWW/green_tree/.git/index.lock': File exists.解决办法

    找到自己的项目,找到.git文件夹,进去把目标文件删除即可 或者使用rm -rf 命令(如果没有那个文件件或者文件,将隐藏文件打开就可以看到了)

  9. 4,版本控制git --忽略特殊文件

    有些时候,你必须把某些文件放到Git工作目录中,但又不能提交它们,比如保存了数据库密码的配置文件啦,等等,每次git status都会显示Untracked files ...,有强迫症的童鞋心里肯定 ...

  10. ansible-3

    setup ansible_all_ipv4_addresses # ipv4的所有地址 ansible_all_ipv6_addresses # ipv6的所有地址 ansible_date_tim ...