YBT 2.4 AC自动机
其实这个专题NOIP几乎不考
AC自动机,就是能让题自动AC的东西,是不是十分神奇
对的,就是这么神奇
AC自动机是解决多模式串与文本串匹配的问题
是KMP+Trie树的结合,也是一个毒瘤算法
Keywords Search
link
此题是AC自动机的板子,刚才说过AC自动机是解决匹配问题的,这道题便如此
板子题,记录结尾即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
int t,n;
int bo[],tot,ch[][];
char str[];
void insert(char *str)
{
int u=;
int len=strlen(str);
for(int i=;i<len;i++)
{
int c=str[i]-'a';
if(ch[u][c]==) ch[u][c]=++tot;
u=ch[u][c];
}
bo[u]++;
return;
}
int nex[],que[];
void bfs()
{
que[]=,nex[]=;
int head=,tail=;
while(head<=tail)
{
int t=que[head]; head++;
for(int i=;i<=;i++)
{
if(ch[t][i]==) ch[t][i]=ch[nex[t]][i];
else{
que[++tail]=ch[t][i];
int v=nex[t];
nex[ch[t][i]]=ch[v][i];
}
}
}
}
int ans;
void find(char *str)
{
int u=,k;
int len=strlen(str);
for(int i=;i<len;i++)
{
int c=str[i]-'a';
k=ch[u][c],u=ch[u][c]; while(k>)
{
ans+=bo[k];
bo[k]=;
k=nex[k];
} }
return;
}
int main()
{
t=read();
while(t--)
{
ans=;
tot=;
memset(ch,,sizeof(ch));
memset(bo,,sizeof(bo));
for(int i=;i<=;i++) ch[][i]=;
n=read();
for(int i=;i<=n;i++)
{
scanf("%s",str);
insert(str);
} bfs();
scanf("%s",str);
find(str);
cout<<ans<<endl;
}
}
玄武密码
link
此题求模式串在文本串前缀最大匹配长度
所以让文本串在AC自动机上走一遍,用flag记录经过的点
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
int n,m,le[];
char cx(char u)
{
if(u=='E') return '';
if(u=='S') return '';
if(u=='W') return '';
if(u=='N') return '';
}
int fa[],ch[][],tot;
bool flag[];
char str[];
int nex[];
int que[];
char s[];
int son[];
void insert(char *str,int an)
{
int u=;
int len=strlen(str);
le[an]=len;
for(int i=;i<len;i++)
{
int c=str[i]-'';
if(ch[u][c]==) ch[u][c]=++tot,fa[tot]=u;
u=ch[u][c];
}
son[an]=u;
return;
} void bfs()
{
nex[]=,que[]=;
int head=,tail=;
while(head<=tail)
{
int x=que[head];head++;
for(int i=;i<;i++)
{
if(ch[x][i]==) ch[x][i]=ch[nex[x]][i];
else{
que[++tail]=ch[x][i];
nex[ch[x][i]]=ch[nex[x]][i];
}
}
}
return;
}
int ls;
void find(char *s)
{
int u=,k;
for(int i=;i<ls;i++)
{
int c=s[i]-'';
k=ch[u][c];
while(k>)
{
if(flag[k]) break; flag[k]=;
k=nex[k];
}
u=ch[u][c];
}
return;
}
int work(int an)
{
int u=son[an];
for(int i=le[an];i>=;i--)
{
if(flag[u]) return i;
u=fa[u];
}
return ;
}
int main()
{
memset(ch,,sizeof(ch));
tot=;
n=read(),m=read();
scanf("%s",s);
for(int i=;i<;i++) ch[][i]=;
ls=strlen(s);
for(int i=;i<ls;i++) s[i]=cx(s[i]);
for(int i=;i<;i++) ch[][i]=;
for(int i=;i<=m;i++)
{
scanf("%s",str);
int l=strlen(str);
for(int j=;j<l;j++) str[j]=cx(str[j]);
insert(str,i);
}
bfs();
find(s);
for(int i=;i<=m;i++) printf("%d\n",work(i));//cout<<work(i)<<endl;
}
Censoring
link
也是让文本串在AC自动机上跑,然后记录一下位置
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
char str[];
int n;
int ch[][],tot;
char s[];
int que[],nex[];
int bo[];
void insert(char *s)
{
int len=strlen(s);
int u=;
for(int i=;i<len;i++)
{
int c=s[i]-'a';
if(ch[u][c]==) ch[u][c]=++tot;
u=ch[u][c];
}
bo[u]=len;
return;
}
void bfs()
{
int head=,tail=;
que[]=,nex[]=;
while(head<=tail)
{
int x=que[head];head++;
for(int i=;i<;i++)
{
if(ch[x][i]==) ch[x][i]=ch[nex[x]][i];
else{
que[++tail]=ch[x][i];
nex[ch[x][i]]=ch[nex[x]][i];
}
}
}
return;
}
int stk1[],stk2[];
void find(char *str)
{
int u=;
int tot=;
int len=strlen(str);
for(int i=;i<len;i++)
{
int c=str[i]-'a';
u=ch[u][c];
stk1[++tot]=u;
stk2[tot]=i;
while(bo[u])
{
tot-=bo[u];
u= stk1[tot];
}
}
for(int i=;i<=tot;i++) cout<<str[stk2[i]];
cout<<endl;
}
int main()
{
tot=;
for(int i=;i<;i++) ch[][i]=;
scanf("%s",str);
n=;
for(int i=;i<=n;i++)
{
scanf("%s",s);
insert(s);
}
bfs();
find(str);
}
单词(待补此坑)
最短母串(待补此坑)
病毒
link
此题是不让文本串在AC自动机上跑到每个模式串的末尾
所以想这个问题,如果说你有无穷长度的文本串
在AC自动机上跑着,但是不让他经过末尾
所以说这个图是有环的,AC自动机不是因为节省时间直接相连nex吧,所以好像这个叫做fail图
所以看一下在AC自动机中不经过每个字符串尾端是否有环即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
inline int read()
{
int f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
char s[];
int tot,st[];
int ch[][];
int n;
int quee[],nex[];
void insert(char *s)
{
int len=strlen(s),u=;
for(int i=;i<len;i++)
{
int c=s[i]-'';
if(!ch[u][c]) ch[u][c]=++tot;
u=ch[u][c];
}
st[u]=;
return;
}
void bfs()
{
int head=,tail=;
quee[]=,nex[]=;
while(head<=tail)
{
int x=quee[head];head++;
for(int i=;i<=;i++)
{
if(ch[x][i]==) ch[x][i]=ch[nex[x]][i];
else{
quee[++tail]=ch[x][i];
nex[ch[x][i]]=ch[nex[x]][i];
if(st[nex[ch[x][i]]]) st[ch[x][i]]++;
}
}
}
return;
}
int vis1[],vis2[];
bool flag;
void dfs(int f)
{
if(flag) return;
vis2[f]=;
for(int i=;i<=;i++)
{
int s=ch[f][i];
if(flag) return;
if(st[s]) continue;
if(vis2[s])
{
flag=;
cout<<"TAK";
return;
}
if(flag) return;
if(vis1[s]) continue;
vis1[s]=;
dfs(s);
}
vis2[f]=;
}
int main()
{
tot=;
n=read();
for(int i=;i<=;i++) ch[][i]=;
for(int i=;i<=n;i++) scanf("%s",s),insert(s);
bfs();
flag=false;
dfs();
if(flag==) cout<<"NIE";
return ;
}
/*
2
1
0
*/
文本生成器
link
第一次在AC自动机上跑dp
想一个问题,如果这个有m长度的文本串符合条件的话,他至少是一个模式的母串吧
你怎么去统计呢,有可能是一个,两个,三个,四个~~~
在数学上有一种想法是退而求进,所以可以把这道题转换成有多少个无法模式串匹配的情况
这时候求的就是0了,然后去拿总可能-这种可能便是答案
为什么说这一道题是dp呢,因为满足dp的思想了
dp[i]为长度为i有多少个
但是无法往前推
所以再加一维,加什么呢
很容易想到是访问在哪个节点吧
所以dp模型就已经定下来了
dp[i][j]表示现在长度为i,节点是j共有多少个串
AC自动机有什么用呢,其实就是建图有用
将字符串转换成一张图
不让他走末尾节点
所以现在就有一个要注意的坑点了
***当你找到一点x,若此点的nex是一个字符串的结尾,所以这个x其实就是一个病毒了
其实就是每人对nex理解了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mod 10007
using namespace std;
inline long long read()
{
long long f=,ans=;char c;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){ans=ans*+c-'';c=getchar();}
return f*ans;
}
long long n,m,tot,u,ch[][],bo[];
char s[];
void insert(char *s)
{
long long len=strlen(s),u=;
for(long long i=;i<len;i++)
{
long long c=s[i]-'A';
if(!ch[u][c]) ch[u][c]=++tot;
u=ch[u][c];
}bo[u]=;
return;
}
long long que[],nex[];
void bfs()
{
long long head=,tail=;
que[]=,nex[]=;
while(head<=tail)
{
long long xx=que[head];head++;
for(long long i=;i<;i++)
{
if(ch[xx][i]==) ch[xx][i]=ch[nex[xx]][i];
else{
que[++tail]=ch[xx][i];
nex[ch[xx][i]]=ch[nex[xx]][i];
bo[ch[xx][i]]|=bo[ch[nex[xx]][i]];
}
}
}
return;
}
long long dp[][];
int main()
{
for(long long i=;i<;i++) ch[][i]=;
tot=;
n=read(),m=read();
for(long long i=;i<=n;i++)
{
scanf("%s",s);
insert(s);
}
bfs();
dp[][]=;
for(long long i=;i<=m;i++)
for(long long j=;j<=tot;j++)
for(long long z=;z<;z++)
if(!bo[ch[j][z]]) dp[i][ch[j][z]]+=dp[i-][j],dp[i][ch[j][z]]%=mod;
long long ans=;
for(long long i=;i<=tot;i++) ans+=dp[m][i],ans%=mod;
long long sum=;
for(long long i=;i<=m;i++) sum*=,sum%=mod;
cout<<(sum-ans+mod)%mod;
}
YBT 2.4 AC自动机的更多相关文章
- 021(Keywords Search)(AC自动机)
题目:http://ybt.ssoier.cn:8088/problem_show.php?pid=1479 题目思路:一道AC自动机的模板题 备注:还不会字典树和KMP的尽早回去重修 如果让你在一篇 ...
- 基于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 ...
- AC自动机 HDU 3065
大概就是裸的AC自动机了 #include<stdio.h> #include<algorithm> #include<string.h> #include< ...
随机推荐
- mysql新手进阶02
云想衣裳花想容,春风拂槛露华浓. 若非群玉山头见,会向瑶台月下逢. 现在有一教学管理系统,具体的关系模式如下: Student (no, name, sex, birthday, class) Tea ...
- 树和二叉树 -数据结构(C语言实现)
读数据结构与算法分析 树的概念 一棵树是一些节点的集合,可以为空 由称做根(root)的节点以及0个或多个非空子树组成,子树都被一条来自根的有向边相连 树的实现 思路 孩子兄弟表示法:树中的每个节点中 ...
- NOIP2019普及级别模拟 3.30校模拟
好吧我还是第一次写这种总结类的玩意… 考场心情…hmm…我没睡醒.是的是这样的,反正题都有两三个看错了或者没看懂… 最关键的是!!我!居!然!把!Freopen!写!在!了!程!序!最!后! 然后就和 ...
- fp-growth树创建代码及详细注释
事务集过滤重排: #FP树节点结构 class treeNode: def __init__(self,nameValue,numOccur,parentNode): self.name=nameVa ...
- usb_modeswitch移植
usb_modeswitch移植 交叉工具链安装 交叉编译安装libsub库 交叉编译安装lib-compat-x.x.x 交叉编译安装usb_modeswitch 交叉编译工具链 为了使编译的程序可 ...
- hadoop参数(未完).md
我X,有违禁词.麻烦提醒一下哪个词好吗?
- BZOJ 4361 isn 容斥+dp+树状数组
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4361 题意概述: 给出一个长度为N的序列A(A1,A2...AN).如果序列A不是非降的 ...
- lintcode-186-最多有多少个点在一条直线上
186-最多有多少个点在一条直线上 给出二维平面上的n个点,求最多有多少点在同一条直线上. 样例 给出4个点:(1, 2), (3, 6), (0, 0), (1, 3). 一条直线上的点最多有3个. ...
- Agile.Net 组件式开发平台 - 驱动开发示例
首先讲一下概念,此驱动非彼驱动.在Agle.Net中我们将组件规划成两种类型,一种是基于业务的窗体组件,一种是提供扩展功能的驱动组件. 打个比方例如一般系统中需要提供身份证读卡功能,然而市面上有很多种 ...
- java数组相等
java中数组相等判断: 1.最常规的是遍历 public static boolean arrayEquals(String[] a,String[] b){ boolean flag = fals ...