非线性字符串数据结构串讲

书接去年,今天作业不想写了,滚过来写总结。顺便保留我刚略微学会的串串。

声明:作者由于水平不高,所以有些定理不能严谨证明,所以若是初学者请移步别处。

1.Trie树

定义

Trie树又叫字典树,是非常显然的一种字符串数据结构。

具体来说,我们如果手上有很多字符串,我们可以通过建一个Trie树来做一些简单的操作。

其构建过程可以看一下图,非常显然,本质就是把字符串的相同部分压缩一下。

比如我们对

复制代码
aa

aba

ba

caaa

cab

cba

cc

建一个Trie就长这样。

构建

图来自OI wiki

然后构建这块也挺简单的

代码

cpp 复制代码
int len,idx,cnt[N],tr[N][70];
ll getid(char c){
	if(c>='A'&&c<='Z') return c-'A';
	else if(c>='a'&&c<='z') return c-'a'+26;
	else return c-'0'+52;
}
void add(string s){
	len=s.size();
	s=' '+s;
	int p=0;
	for(int i=1;i<=len;i++){
		int id=getid(s[i]);
		if(!tr[p][id]) tr[p][id]=++idx;
		p=tr[p][id];
		cnt[p]++;
	}
}
ll ask(string s){
	len=s.size();
	s=' '+s;
	int p=0;
	for(int i=1;i<=len;i++){
		int id=getid(s[i]);
		if(!tr[p][id]) return 0;
		p=tr[p][id];
	}
	return cnt[p];
}

空间这块,最坏情况每个字符串的每个字符都要新开一个节点,所以空间开即可。

上一道例题

AT_arc219_a ARC219A Similarity

AT_arc219_a ARC219A Similarity

正难则反

这个比较困难

所以就把S串01翻转,那么就是找出一个串串使得不能与任何一个S串相同。

那你给这些反串建出Trie后,找一个还没有被经过的节点即可。

例题结束

与异或相关

其实我们的Trie树不只能在字符串上用

因为在我们眼里数是有二进制的,二进制我们就可以想到01串。

我们就可以把数字当做01串建Trie树

当我们遇到一些神秘有关异或的题目时,

我们一想Trie树,二想线性基

比如来道题,给定你一个序列和x值,让你从这个序列中选一个元素,使之其与x的异或值最大。

考虑异或的性质,二进制位上不同为一,相同为0。

所以我们对序列建Trie树,把给定的x二进制分解,从高往低位的贪心的尽可能与x当前位不同。就行了。

来一道有意思的应用

P5283 十二省联考 2019 异或粽子

题解

2.AC自动机

定义

AC自动机,由两部分构成Trie树和fail树。

AC自动机的本质上就是建出Trie树后连fail边。

这里我们给出fail边的定义。

在Trie树上,每一个节点表示一个字符串。

fail边指向这个节点所代表的字符串 最长的后缀 所代表的节点。

图例

example:

图来自OI wiki

比如这个Trie树

给他建fail边就应该是这样的

由于根节点代表的是空串,空串是任何字符串的后缀。

所以当你实在在Trie树上找不到后缀时,就直接无脑连根结点就可以啦。

然后AC自动机的功能这块,可以通过拿一个字符串在上面跑得到在自动机上他的所有子串,不管通过Trie边还是fail边。

代码

cpp 复制代码
int n,m,len,idx=1;
string s;
struct trie{
	int son[29],fail;
	int flag;
}t[N];
struct AC_automation{
	void build(string s){
		len=s.size(); s=' '+s;
		int p=0;
		for(int i=1;i<=len;i++){
			int v=s[i]-'a'+1;
			if(!t[p].son[v]) t[p].son[v]=++idx;
			p=t[p].son[v];
		}
		t[p].flag++;
	}
	void getfail(){
		queue<int> q;
		for(int i=1;i<=26;i++) if(t[0].son[i]) q.push(t[0].son[i]);
		while(!q.empty()){
			int p=q.front();
			q.pop();
			for(int i=1;i<=26;i++){
				int v=t[p].son[i];
				int faf=t[p].fail;
				if(!v){
					t[p].son[i]=t[faf].son[i];
					continue;
				}
				t[v].fail=t[faf].son[i];
				q.push(v);
			}
		}
	}
	ll ask(string s){
		len=s.size(); s=' '+s;
		int p=0; ll ans=0;
		for(int i=1;i<=len;i++){
			int v=s[i]-'a'+1;
			int k=t[p].son[v];
			while(k>1&&t[k].flag!=-1){
				ans+=t[k].flag,t[k].flag=-1;
				k=t[k].fail;
			}
			p=t[p].son[v];
		}
		return ans;
	}
	
}AC;

P9613 CERC2019 K==S

大意就是构造一个长度为N的串串,让你是这个串串不包含给出的禁用短语作为子串,求方案数。

多模匹配想到建AC自动机并建图,由于不能含某些子串,所以不能走到这些子串的节点以及能通过跳fail边到这些子串的地方。

发现N很大,直接DP不行。但是状态转移固定,所以使用矩阵乘法优化DP就好了。

3.后缀数组

其实有点跑题了,因为后缀数组是线性的,但是后缀数组比较困难所以就写在这里了

定义

性质

图文来自洛谷

代码

cpp 复制代码
string s;
int sa[N],c[N],x[N],y[N],height[N],rk[N];
namespace SA{
	void getsa(){
		for(int i=1;i<=n;i++)++c[x[i]=s[i]];
		for(int i=2;i<=m;i++)c[i]+=c[i-1];
		for(int i=n;i;i--)sa[c[x[i]]--]=i;
		for(int k=1;k<=n;k*=2){
			int num=0;
			for(int i=n-k+1;i<=n;i++)y[++num]=i;
			for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
			for(int i=1;i<=m;i++)c[i]=0;
			for(int i=1;i<=n;i++)++c[x[i]];
			for(int i=2;i<=m;i++)c[i]+=c[i-1];
			for(int i=n;i;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
			swap(x,y);
			x[sa[1]]=1;
			num=1;
			for(int i=2;i<=n;i++){
				x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
			}
			if(num==n)break;
			m=num;
		}
	}
	void getheight(){
		for(int i=1;i<=n;i++) rk[sa[i]]=i;
		int k=0;
		for(int i=1;i<=n;i++){
			if(rk[i]==1) continue;
			if(k) k--;
			int j=sa[rk[i]-1];
			while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k]) k++;
			height[rk[i]]=k;
		}
	}
}
using namespace SA;

4.后缀自动机

相关推荐
青少儿编程课堂1 小时前
蓝桥杯青少组图形化 STEMA 省考(报名倒计时·11/22开考)+ 全国青少年信息素养大赛 2026—2027赛季 + 电子学会图形化考级:校园华容道大闯关
c++·python·算法·bfs·信息学竞赛
白杨尚青1 小时前
C++进阶篇(五):红黑树——四条规则、三种插入情况与旋转变色
开发语言·数据结构·c++·stl·红黑树·平衡二叉树
橙橙笔记1 小时前
QT的学习第四部分
linux·qt·学习·音视频
叼烟扛炮2 小时前
Linux 学习笔记(五十四):内网穿透实战——用 frp 让外网访问你的私人电脑
linux·服务器·网络·笔记·学习
在猴站学算法2 小时前
(《统计学习方法》(第2版) 李航)第2章 感知机算法
学习·算法·机器学习·统计学习
Rainmicro2 小时前
【无标题】
java·数据库·算法
旖旎夜光2 小时前
【C++ 基础入门】C++ 继承(上):概念、切片、隐藏、默认成员函数与友元
c++·笔记·学习
Godspeed Zhao2 小时前
从零开始学AI24——无监督学习之K均值
学习·机器学习
叼烟扛炮2 小时前
[LangChain] 学习笔记(05):提示词模板(Prompt)与少样本注入(Few-Shot)实战
linux·人工智能·笔记·学习·langchain·prompt