【学习笔记】AC自动机(ACAM)

1.【代码】

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;int n;
int trans[N][26];
int cnt=0;
int fail[N];
int to[N];
int insert(string s){
	int now=0;
	for(auto v:s){
		if(!trans[now][v-'a']) trans[now][v-'a']=++cnt;
		now=trans[now][v-'a'];
	}
	return now;
}
vector<int> mp[N];
void Fail(){
	queue<int> q;
	for(int i=0;i<=25;i++){
		if(trans[0][i]) q.push(trans[0][i]);
	}
	while(q.size()){
		int u=q.front();q.pop();
		//cout<<u<<" ";
		for(int i=0;i<=25;i++){
			if(trans[u][i]){
				fail[trans[u][i]]=trans[fail[u]][i];
				q.push(trans[u][i]);
			}
			else trans[u][i]=trans[fail[u]][i];//变成了trie图
		}
	}
	for(int i=1;i<=cnt;i++) mp[fail[i]].push_back(i);
}
int num[N];
void dfs(int u){
	for(auto v:mp[u]){
		dfs(v);
		num[u]+=num[v];
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		string s;cin>>s;
		to[i]=insert(s);
	}
	Fail();
	string s;cin>>s;
	int now=0;
	for(auto v:s){
		now=trans[now][v-'a'];
		num[now]++;
	}
	dfs(0);//暴力跳fail,转差分统计
	for(int i=1;i<=n;i++) cout<<num[to[i]]<<"\n";
	return 0;
}

2.【指针】

  • Trie指针,即字典树上的边

  • Fail指针:适配后的跳转指针

  • 末指针:Fail指针的子集,只在末尾出现

3.【优化】

暴力跳fail,转为拓扑差分求和,这个优化是必须的

//朴素做法
// 每匹配一个字符,就暴力跳fail链
for(auto v:s){
    now = trans[now][v-'a'];
    int tmp = now;
    while(tmp){
        num[tmp]++;
        tmp = fail[tmp];
    }
}
//差分优化
// 匹配时:只记录节点访问次数
num[now]++;

// 匹配结束后:在fail树上累加
dfs(0);  // 子节点贡献给父节点

4.【Trie树与Trie图】

构建 fail 时,我们将 \(trans[u][i]\) 缺失的边补全为 \(trans[fail[u]][i]\)

这样做的好处:匹配时无需判断边是否存在,直接 now = trans[now][c] 即可,时间复杂度严格 O(主串长度)。

坏处:原始 Trie 树结构被破坏,无法再进行 DFS 遍历。

5.【一些理解】

  • AC自动机的核心是fail指针建立,后面的query是在其上面做一些其他操作

  • trie和fail可以拆开,Trie 树上的祖先节点代表前缀;fail 指针指向的节点代表最长后缀,沿着 fail 链跳能得到所有后缀。

6.【应用】

6.1【自动机上dp】

P3041 [USACO12JAN] Video Game G

不可以 dfs(因为trie图有环),需要用分层DP

6.2【无限长不匹配】

P2444 [POI 2000 R1] 病毒

标记所有模式串结束节点及其 fail 子树(这些节点不能走)

在剩余节点构成的 Trie 图上找环

如果存在环 → 可以无限走 → 答案存在

6.3【离线多组询问】

P2414 [NOI2011] 阿狸的打字机

需要保留原始Trie树(用于DFS序)

在 fail 树上做树状数组/线段树维护

核心思想:fail 树上的子树代表所有以该节点为后缀的串

posted @ 2026-08-25 08:48  Aistyr  阅读(3)  评论(0)    收藏  举报