fzu 2246(ac 自动机)

题意:

某一天YellowStar学习了AC自动机,可以解决多模式匹配问题。YellowStart当然不会满足于此,它想进行更深入的研究。

YellowStart有一个母串\(S\),以及\(m\)个询问串\(T\),它发现如果把母串删除掉一个子串,把剩余的串按原先顺序拼接起来,某些询问串\(T\)就可能出现在这个新的母串中。

现在,对于第\(i\)个询问串\(T_i\),YellowStar想知道,母串最多可以删除多长的子串,使得该询问串出现在新的母串的子串中。

\(|S| <= 1e5\)

$\sum{|T_i|} <= 1e5 $

思路:利用ac自动机处理出每个查询串的每个前缀在S中最先出现的位置 和 每个后缀在S中最后出现的位置,取

\(max(sufpos[i+1] - prepos[i] - 1)\)即可

具体的做法 是将所有询问串 正着一遍插入ac自动机,对于串S 类似于找子串的方式更新当前位置匹配的所有前缀,然后再反着插入做一遍即可

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#define LL long long
using namespace std; const int N = 1e5 + 10;
char S[N],P[N],tmp[N],S_r[N];
int m, tot;
int len[N],st[N];
int pre_id[N],suf_id[N];
int pre_pos[N],suf_pos[N];
const int SIZE = 26;
const int MAXNODE = 1e5 + 10; struct AC{
int ch[MAXNODE][SIZE];
int f[MAXNODE],last[MAXNODE],val[MAXNODE];
int sz;
void init(){sz = 1;memset(ch[0],0,sizeof(ch[0]));}
int idx(char c){return c - 'a';}
int _insert(char *s, int st,int len,int *p){
int u = 0;
for(int i = 0;i < len;i++){
int c = idx(s[i + st]);
if(!ch[u][c]){
memset(ch[sz],0,sizeof ch[sz]);
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
val[u] = 1;
p[i + st] = u;
}
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 up(int u,int x,int *p){
if(!u) return ;
if(p[u] == -2) p[u] = x;
up(last[u],x,p);
}
void Find(char *s,int *p){
int len = strlen(s), u = 0;
pre_pos[u] = -1;
for(int i = 0;i < len;i++){
int c = idx(s[i]);
u = ch[u][c];
up(u,i,p);
}
}
}ac;
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%s",P);
scanf("%d",&m);
tot = 0;
for(int i = 0;i < m;i++){
scanf("%s",tmp);
len[i] = strlen(tmp);
st[i] = tot;
for(int j = 0;j < len[i];j++) S[j + tot] = tmp[j];
reverse(tmp,tmp + len[i]);
for(int j = 0;j < len[i];j++) S_r[j + tot] = tmp[j];
tot += len[i];
}
for(int i = 0;i < tot;i++) pre_pos[i] = suf_pos[i] = -2;
ac.init();
for(int i = 0;i < m;i++) ac._insert(S,st[i],len[i],pre_id);
ac.getFail();
ac.Find(P,pre_pos);
ac.init();
for(int i = 0;i < m;i++) ac._insert(S_r,st[i],len[i],suf_id);
ac.getFail();
int tlen = strlen(P);
reverse(P,P + tlen);
ac.Find(P,suf_pos);
for(int i = 0;i < m;i++){
int ans = -1;
int stt = st[i],ll = len[i];
if(pre_pos[pre_id[stt + ll - 1]] != -2) ans = max(ans, tlen - pre_pos[pre_id[stt + ll - 1]] - 1);
if(suf_pos[suf_id[stt + ll - 1]] != -2) ans = max(ans, tlen - suf_pos[suf_id[stt + ll - 1]] - 1);
for(int j = 0;j + 1 < ll;j++){
int a = pre_pos[pre_id[j + stt]];
int b = suf_pos[suf_id[ll - j - 2 + stt]];
if(a != -2 && b != -2 && tlen - b -1 - a - 1 >= 1) ans = max(ans,tlen - b - 1 - a - 1);
}
printf("%d\n",ans);
}
}
return 0;
}

fzu 2246(ac 自动机)的更多相关文章

  1. fzu 2128 AC自动机

    链接   http://acm.fzu.edu.cn/problem.php?pid=2128 解题方法  首先考虑暴力,,就是拿每一个字符串在匹配串里面找到所有位置,然后从头到尾不断更新最长的合理位 ...

  2. HDU 3341 Lost's revenge AC自动机+dp

    Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)T ...

  3. 基于trie树做一个ac自动机

    基于trie树做一个ac自动机 #!/usr/bin/python # -*- coding: utf-8 -*- class Node: def __init__(self): self.value ...

  4. AC自动机-算法详解

    What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. 简单的说,KMP用来在一篇文章中匹配一个模式串:但 ...

  5. python爬虫学习(11) —— 也写个AC自动机

    0. 写在前面 本文记录了一个AC自动机的诞生! 之前看过有人用C++写过AC自动机,也有用C#写的,还有一个用nodejs写的.. C# 逆袭--自制日刷千题的AC自动机攻克HDU OJ HDU 自 ...

  6. BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

    2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Sta ...

  7. BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]

    3172: [Tjoi2013]单词 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 3198  Solved: 1532[Submit][Status ...

  8. BZOJ 1212: [HNOI2004]L语言 [AC自动机 DP]

    1212: [HNOI2004]L语言 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1367  Solved: 598[Submit][Status ...

  9. [AC自动机]【学习笔记】

    Keywords Search Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)To ...

随机推荐

  1. virtual box 故障修复

    vmware ,virtual box等虚拟化环境为一台系统同时允许运行多台系统成为可能准备了技术支持. 通过软件化的平台虚构出硬件设备的驱动,可谓虚拟化技术应用非常广泛. 在平常的虚拟机启动过程中经 ...

  2. Volatile的详解

    volatile关键字修饰的共享变量主要有两个特点:1.保证了不同线程访问的内存可见性    2.禁止重排序 在说内存可见性和有序性之前,我们有必要看一下Java的内存模型(注意和JVM内存模型的区分 ...

  3. 基于vue来开发一个仿饿了么的外卖商城(二)

    一.抽出头部作为一个组件,在底部导航的时候可以相应的显示不同的标题 技术点:使用slot进行组件间的通信:父组件给子组件传值(子组件里面通过props接收父组件传过来的数据) 查看链接:https:/ ...

  4. c++ map的使用方法

    1.头文件:#include<map> 2.定义:map<typename1,typename2> mp 注:字符串数组只能用string而不能使用char[] 3.访问方式: ...

  5. 从0开始 java 网站开发(jsp)【1】

    前提:安装java 并配置环境变量 java下载地址: http://www.java.com/zh_CN/ 环境变量配置 本地PC路径: 电脑--属性--高级--环境变量 在系统变量中: 新建 名: ...

  6. elasticsearch 关联查询

    父-子关系文档 父-子关系文档 在实质上类似于 nested model :允许将一个对象实体和另外一个对象实体关联起来. 而这两种类型的主要区别是:在 nested objects 文档中,所有对象 ...

  7. 使用Visual Studio 2017构建.Net Core的Docker镜像

    1 Docker  镜像优化 微软在为开发人员生成 Docker 镜像时,提供以下三种主要方案: 用于开发 .NET Core 应用的 镜像 用于构建生成 .NET Core 应用的 镜像 用于运行 ...

  8. IDEA的terminal设置成Linux的终端一样

    方式一:通过在Windows上安装Linux命令行工具 前提:需要安装Linux终端的命令行工具,并且最好可以安装 Gow (一个Windows下模拟Linux命令行工具集合,它集成了 Liunx 环 ...

  9. Sleuth+Zipkin+Log

    https://blog.csdn.net/sqzhao/article/details/70568637 https://blog.csdn.net/yejingtao703/article/det ...

  10. 开发react的一些记录

    1.keyboard事件返回的对象SyntheticKeyboardEvent全部是null 解决方法:SyntheticKeyboardEvent的type,which,timeStamp可以得到你 ...