首页 > 其他分享 >CHY 自动机

CHY 自动机

时间:2022-11-08 09:23:09浏览次数:68  
标签:AC Trie text 复杂度 CHY 自动机

\(\text{CHY}\) 自动机


『这个不是直接 \(\text{AC}\) 自动机吗?』

『怎么 \(\text{AC}\) 自动机?』

『搞棵 \(\text{Trie}\) 出来,然后在上面挂指针,拿节点去做数位 \(\text{DP}\) 就好了。』

『你怎么挂的指针?』

『就直接对每个串跑 \(\text{KMP}\) 挂指针。』

『这个不是 \(\text{AC}\) 自动机。』

『不是吗,\(\text{AC}\) 自动机不就是 \(\text{KMP+Trie}\) 吗?』

『\(\text{AC}\) 自动机指针是挂在 \(\text{Trie}\) 树上 \(\text{BFS}\) 序小于自己的最长公共前后缀上的,你直接挂是暴力。』

『反正就是拿 \(\text{Trie}\) 树的节点去数位 \(\text{DP}\) 可以吧。』

And God said, Let there be automaton: and there was automaton.

正如上面所说,\(\text{CHY}\) 自动机与 \(\text{AC}\) 自动机的区别就在于失配指针所指向的节点,\(\text{CHY}\) 自动机的失配指针指向的一定是当前节点的祖先。

这会造成什么差异呢?


复杂度分析

\(\text{AC}\) 自动机按照 \(\text{Trie}\) 树的 \(\text{BFS}\) 序构建,而 \(\text{CHY}\) 自动机可以按照 \(\text{Trie}\) 树的 \(\text{DFS}\) 序构建。

构建 \(\text{CHY}\) 自动机的流程实际上就是一个 \(\text{DFS}\) 整棵 \(\text{Trie}\) 树并进行带撤销的 \(\text{KMP}\)。

因为 \(\text{KMP}\) 的时间复杂度是均摊的,所以它的时间复杂度为 \(\mathcal{O}(\sum|s|)\)(与总串长成线性),空间复杂度为 \(\mathcal{O}(|\Sigma| \cdot \sum|s|)\)(与 \(\text{Tire}\) 树点数成线性)。

相比之下,\(\text{AC}\) 自动机的时间复杂度与空间复杂度均为 \(\mathcal{O}(|\Sigma| \cdot \sum|s|)\)(与 \(\text{Trie}\) 树点数成线性),逊色于 \(\text{CHY}\) 自动机。

为什么它们的时间复杂度会有差异呢?

考虑时间复杂度相同的广义后缀自动机,发现二者维护的均为文本串,而 \(\text{AC}\) 自动机维护的是模式串。

模式串在后缀自动机上匹配,不存在失配后的二次转移;但文本串在 \(\text{AC}\) 自动机上匹配,需要考虑失配后的转移,所以 \(\text{AC}\) 自动机的每个节点都必须建出规模为字符集大小的转移以保证时间复杂度。 若 \(\text{CHY}\) 自动机也对每个节点建出字符集大小的转移,可以得到与 \(\text{AC}\) 自动机同样的复杂度(与 \(\text{Trie}\) 树点数成线性)。

在不对字符集所有元素建出转移的前提下,\(\text{CHY}\) 自动机的空间瓶颈在于 \(\text{Trie}\) 树,所以我们可以使用 \(\text{Hash}\) 表再对 \(\text{CHY}\) 自动机空间复杂度进行优化,在选取模数优秀,字符集元素可以 \(\text{O}(1)\) 比较的前提下,其时间复杂度与空间复杂度均为 \(\mathcal{O}(\sum|s|)\)。

为了减小码量,我们可以通过牺牲一下时间复杂度,用 STL 中的 map 替代 \(\text{Hash}\) 表,时间复杂度变为 \(\mathcal{O}(f(\Sigma)\sum|s| \log (\sum|s|))\)。\(f(\Sigma)\) 表示字符集元素比较的时间复杂度,通常在 O2 优化下时间效率略胜于不加 O2 优化的 \(\text{Hash}\) 表做法,但空间占用大于 \(\text{Hash}\) 表做法。


应用

这里我们以 \(\text{CHY}\) 自动机模板题 为例。

给定 \(n\) 个文本串。

有 \(m\) 组询问,每组询问给出模式串 \(s\),求 \(n\) 个文本串的前缀集合中有多少个串的 \(\text{border}\) 集合包含 \(s\)。

数据范围:字符串均由小写字母构成,文本串与模式串总长均不超过 \(5 \times 10^6\)。

多模式多文本,至少一个插到 \(\text{Trie}\) 树上。

发现模式插到 \(\text{Trie}\) 上,\(\text{AC}\) 自动机带个 \(26\),可以卡,考虑 \(\text{CHY}\) 自动机。

把文本插到 \(\text{Trie}\) 上,所有节点恰好表示 \(n\) 个文本串的前缀集合,答案就是模式串在 \(\text{CHY}\) 自动机的失配树上的子树大小 \(-1\),模式串失配则答案为 \(0\)。

Code
#include <bits/stdc++.h>
using namespace std;
#define MAXN (int)(5e6+233)
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define mk make_pair

struct Trie
{
	
	int cnt,now,f[MAXN],lst[MAXN],pre[MAXN];
	char tr[MAXN];
	string t;
	vector<char> son[MAXN];
	map<pair<int,char>,int> to;
	
	inline void ins(string &s)
	{
		int x=0;
		for (auto c:s)
		{
			if (to.find(mk(x,c))!=to.end()) x=to[mk(x,c)];
			else son[x].push_back(c),tr[x=to[mk(x,c)]=++cnt]=c;
		}
	}
	
	void dfs(int x)
	{
		while (now&&tr[x]!=tr[lst[now]]) now=pre[now];
		if (x!=lst[0]&&tr[x]==tr[lst[now]]) now=lst[now];
		pre[x]=now;
		for (auto c:son[x]) lst[x]=to[mk(x,c)],dfs(lst[x]),now=pre[x];
		f[now]+=++f[x];
	}
	
	inline int qry(string &s)
	{
		int x=0;
		for (auto c:s)
		{
			if (to.find(mk(x,c))!=to.end()) x=to[mk(x,c)];
			else return 0;
		}
		return f[x]-1;
	}
	
} trie;

int n,m;
string s;

inline int read()
{
	int x=0,f=1;char c;
	while (!isdigit(c=getchar())) if (c=='-') f=-1;
	while (isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return f*x;
}

signed main()
{
	n=read(),m=read();
	rep(i,1,n) cin>>s,trie.ins(s);
	trie.dfs(0);
	rep(i,1,m) cin>>s,printf("%d\n",trie.qry(s));
	return 0;
}

标签:AC,Trie,text,复杂度,CHY,自动机
From: https://www.cnblogs.com/CrH2/p/16868559.html

相关文章

  • 【模板】广义后缀自动机 exSAM
    postedon2022-11-0218:51:48|under模板|sourcesolution膜拜@xzzduang。我们重学一个SAM。一个点维护的是所有\(endpos=S\)的(本质不同的)串,显然这些串的长度......
  • 【模板】AC 自动机
    postedon2022-06-1111:17:10|under模板|sourcetemplate<intN,intM=26,intD='a'>structacam{ intch[N+10][M],cnt[N+10],tot,fail[N+10]; intsum[N+10],i......
  • KMP 自动机,孤独的自动机(同时也是CF1721E的题解)
    给定字符串\(s\),以及\(q\)个串\(t_i\),求将\(s\)分别与每个\(t_i\)拼接起来后,最靠右的\(|t_i|\)个前缀的border长度。询问间相互独立。\(|s|\leq10^6,q......
  • [Alluxio基础]-- 初识 Alluxio(原名 Tachyon )
    1、前言我们有了解分布式文件系统(HDFS)、分布式计算(如Spark),但是肯定有许多小伙伴未曾了解过Alluxio,当然我也未曾深入了解,那么,今天,我们就一起初步了解下Alluxio。它是什么......
  • 后缀自动机
    后缀自动机//CreatedbyCAD#include<bits/stdc++.h>usingnamespacestd;constintmaxn=1e6+5;namespacesam{intlen[maxn<<1],link[maxn<<1],Next[maxn<<1][26];......
  • 【XSY4180】串串游走(AC自动机,期望DP,高斯消元)
    假瑞出搬的神仙题。原题CFgym103119B。先把\(T\)去重。考虑先用\(O(nm\logk)\)建出所有串的AC自动机。注意建AC自动机的时候,为了保证空间,假设当前点\(u\)没......
  • 【XSY3993】自动机(构造)
    题面自动机题解题意:让你构造一个不超过\(n+1\)个状态的自动机,使得\(1\simn\)的\(n!\)个排列中只有\(q\)个被该自动机接受。\(q=n!\)可以先特判掉。然后找......
  • 【XSY2499】字符串(AC自动机+树状数组)
    题面DescriptionUPD:本题字符集为全体小写字母InputOutputSampleInput51abc3abcabc0abc3aba1abababcSampleOutput22HINT题解这个“强制在......
  • P5826 【模板】子序列自动机
    题目链接P5826【模板】子序列自动机【模板】子序列自动机题目背景本题中,若\(x\)是\(y\)的子序列,则等价于存在一个单调递增序列\(z\),满足\(|z|=|x|\),\(z_{|x|}......
  • AC自动机
    \(Kmp\)与\(Trie\)的优美结合,相当于在\(Trie\)上跑\(Kmp\)。一个重要定义:\(Fail\)指针(失配指针),指向其他路径上与该字母相同的节点。当前路径的模式串的后缀与\(fail\)指针......