其实这个专题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自动机的更多相关文章

  1. 021(Keywords Search)(AC自动机)

    题目:http://ybt.ssoier.cn:8088/problem_show.php?pid=1479 题目思路:一道AC自动机的模板题 备注:还不会字典树和KMP的尽早回去重修 如果让你在一篇 ...

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

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

  3. AC自动机-算法详解

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

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

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

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

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

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

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

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

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

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

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

  9. AC自动机 HDU 3065

    大概就是裸的AC自动机了 #include<stdio.h> #include<algorithm> #include<string.h> #include< ...

随机推荐

  1. Linux命令应用大词典-第29章 SELinux管理

    29.1 sestaus:显示SElinux的状态 29.2 getenforce:显示当前SELinux的应用模式 29.3 setenforce:修改SELinux的应用模式 29.4 getfa ...

  2. 213. String Compression【LintCode java】

    Description Implement a method to perform basic string compression using the counts of repeated char ...

  3. 在Arch上安装VSCode的方法

    首先去特硬去下载vscode的安装包 mkdir /tmp/vscode cd /tmp/vscode/ wget https://az764295.vo.msecnd.net/public/0.3. ...

  4. 数据库Mysql的学习(八)-储存过程和事务和导入导出

    储存过程 DELIMITER // CREATE PROCEDURE pro1() BEGIN SELECT book_id,book_name,category FROM bookinfo t1 J ...

  5. ajax的$.get()方法和tomcat服务器的交互

    AJAX AJAX = 异步 JavaScript 和 XML. AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术. Ajax  get()方法 定义和用法 $.get() 方法 ...

  6. 安装sqoop 1.99.4

    参考http://sqoop.apache.org/docs/1.99.4/Installation.html 1.简介 sqoop2分为server和client两部分.server作为maprde ...

  7. [leetcode-784-Letter Case Permutation]

    Given a string S, we can transform every letter individually to be lowercase or uppercase to create ...

  8. POJ 2208 Pyramids(求四面体体积)

    Description Recently in Farland, a country in Asia, a famous scientist Mr. Log Archeo has discovered ...

  9. URAL 1519 Formula 1(插头DP,入门题)

    Description Background Regardless of the fact, that Vologda could not get rights to hold the Winter ...

  10. 11.24Daily Scrum

    人员 任务分配完成情况 明天任务分配 王皓南 实现网页上视频浏览的功能.研究相关的代码和功能.990 测试 申开亮 实现网页上视频浏览的功能.研究相关的代码和功能.991 测试 王宇杰 负责后台代码测 ...