fzu 2246(ac 自动机)
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 自动机)的更多相关文章
- fzu 2128 AC自动机
链接 http://acm.fzu.edu.cn/problem.php?pid=2128 解题方法 首先考虑暴力,,就是拿每一个字符串在匹配串里面找到所有位置,然后从头到尾不断更新最长的合理位 ...
- 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 ...
- 基于trie树做一个ac自动机
基于trie树做一个ac自动机 #!/usr/bin/python # -*- coding: utf-8 -*- class Node: def __init__(self): self.value ...
- AC自动机-算法详解
What's Aho-Corasick automaton? 一种多模式串匹配算法,该算法在1975年产生于贝尔实验室,是著名的多模式匹配算法之一. 简单的说,KMP用来在一篇文章中匹配一个模式串:但 ...
- python爬虫学习(11) —— 也写个AC自动机
0. 写在前面 本文记录了一个AC自动机的诞生! 之前看过有人用C++写过AC自动机,也有用C#写的,还有一个用nodejs写的.. C# 逆袭--自制日刷千题的AC自动机攻克HDU OJ HDU 自 ...
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2545 Solved: 1419[Submit][Sta ...
- BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]
3172: [Tjoi2013]单词 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3198 Solved: 1532[Submit][Status ...
- BZOJ 1212: [HNOI2004]L语言 [AC自动机 DP]
1212: [HNOI2004]L语言 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1367 Solved: 598[Submit][Status ...
- [AC自动机]【学习笔记】
Keywords Search Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)To ...
随机推荐
- python3 练习题100例 (二十八)打印一定范围内的素数
题目内容: 给定一个大于2的正整数n,打印出小于n(不包括n且n不大于100)的所有素数. 要求将符合条件的输出填入一个列表中,打印的结果为该列表. 输入格式: 共一行,为一个大于2的正整数 输出格式 ...
- 贪心算法之Huffman
Huffman编码,权重越大,离根节点越大.所以就是不断的选取两个最小的树,然后组成一颗新树,加入集合,然后去除已选的两棵树.不断的循环,直到最后的树的集合只剩下一棵,则构建完成,最后输出Huffma ...
- ABS(引数と同じ大きさの正の数を返す)
ABS 関数 [数値] 数値式の絶対値を返します. 構文 ABS( numeric-expression ) パラメータ numeric-expression 絶対値が返される数値. 戻り値 数値 ...
- 一种简单实用的双向电平转换电路3.3V-5V
当你使用3.3V的单片机的时候,电平转换就在所难免了,经常会遇到3.3转5V或者5V转3.3V的情况,这里介绍一个简单的电路,他可以实现两个电平的相互转换(注意是相互哦,双向的,不是单向的!).电路十 ...
- laravel+vue结合使用
SegmentFault 首页 问答 专栏 讲堂 圈子 发现 搜索 立即登录免费注册 在 SegmentFault,学习技能.解决问题 每个月,我们帮助 1000 万的开发者解决各种各样的技术 ...
- Linux 服务器 监控命令
1 top top类似于windows下面的资源管理器.不仅能够从服务器整体上展示服务器的大致情况,还可以看到具体进程 耗费资源的情况. 展示内存.cpu.交换分区等信息 如上图: 第一行主要描述系统 ...
- PostgreSQL 10.0 压缩版的 pgAdmin 不能用的问题
PostgreSQL终于发布10.0正式版了!下载压缩版的更新了一下本机的版本,然后打开pgAdmin的时候总是报错“The application server could not be conta ...
- JS 客户端检测
能力检测 能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力. 能力检测需要注意两点: 先检测达成目的的最常用的特性.因为先检测最常用的特性可以保证代码最优化,因为在多数情况下都可以避免测试多个 ...
- FJOI 2019 游记
(FJOI 2019 滚粗记) Day 0 早上刷了一些水题,然后就上路了. (画图3D好好玩) 来得晚只有十几分钟时间看考场,于是连试机题都没有Ak. Day 1 果然我还是太菜了 走过来的时候再讨 ...
- es6中类的注意事项
class Circle { constructor(radius) { this.radius = radius; Circle.circlesMade++; }; static draw(circ ...