首页 > 其他分享 >后缀数组

后缀数组

时间:2024-08-25 15:38:19浏览次数:7  
标签:limits 后缀 int 数组 -- sa rk

后缀排序

char s[N];
int n,sa[N],rk[N],ork[N<<1];
int buc[N],id[N],pid[N];

bool cmp(int a,int b,int w){return ork[a]==ork[b] && ork[a+w]==ork[b+w];}

void build()
{
	int m=(1<<17),p=0;
	for(int i=1; i<=n; i++) buc[rk[i]=s[i]]++;
	for(int i=1; i<=m; i++) buc[i]+=buc[i-1];
	for(int i=n; i>=1; i--) sa[buc[s[i]]--]=i;
	for(int w=1; ; w<<=1,m=p,p=0)
	{
		for(int i=n; i>n-w; i--) id[++p]=i;
		for(int i=1; i<=n; i++) if(sa[i]>w) id[++p]=sa[i]-w;
		for(int i=0; i<=m+1; i++) buc[i]=0;
		for(int i=1; i<=n; i++) buc[pid[i]=rk[id[i]]]++;
		for(int i=1; i<=m; i++) buc[i]+=buc[i-1];
		for(int i=n; i>=1; i--) sa[buc[pid[i]]--]=id[i];
		for(int i=1; i<=n; i++) ork[i]=rk[i];
		p=0;
		for(int i=1; i<=n; i++) rk[sa[i]]=cmp(sa[i-1],sa[i],w)? p:++p;
		if(p==n) break;
	}
}

求 \(h\) 数组

关键性质:\(h_{rk_i}\ge h_{rk_{i-1}}-1\)

int k=0;
for(int i=1; i<=tot; i++)
{
	if(k) k--;
	while(s[i+k]==s[sa[rk[i]-1]+k]) k++;
	h[rk[i]]=k;
}

应用

1、求任意两个后缀的 LCP

\[\operatorname{lcp}(i,j)=\min\limits_{p=\min(rk_i,rk_j)+1}^{\max(rk_i,rk_j)}h_p \]

2、求本质不同的子串个数

\[\dfrac{n(n+1)}{2}-\sum\limits_{i=2}^n h_i \]

3、与单调栈结合

将 \(h\) 数组倒过来可以得到一个柱状图,这是用单调栈解决问题的基础。以 P4248 [AHOI2013] 差异 为例,求两两后缀 \(\rm lcp\) 之和。

考虑按 \(rk\) 从小到大加入 \(h\)(其实就是依次加入 \(h_{1\sim n}\)),设 \(F(i)=\sum\limits_{p=1}^{i-1}|\operatorname{lcp}(sa_i,sa_p)| =\sum\limits_{p=1}^{i-1}\min\limits_{q=p+1}^i h_q\),答案即 \(\sum F(i)\)。用单调栈拆掉那个 \(\min\),变成维护单调栈矩形面积和。这是我们熟悉的问题。

一些题目

CF822E Liar

考虑朴素 DP,设 \(f_{i,j}\) 表示匹配到 \(s\) 的第 \(i\) 位,\(t\) 的第 \(j\) 位的最小次数,转移即考虑 \(s[i+1:]\) 和 \(t[j+1:]\) 的最长公共前缀。考虑优化,注意到 \(x\leq 30\),所以值域定义域互换,设 \(f_{i,a}\) 表示用了 \(s\) 前 \(i\) 位,\(a\) 个子串,最远能匹配到 \(t\) 的哪一位。转移不表。

P2178 [NOI2015] 品酒大会

因为是 \(r\) 相似也就一定是 \(0\sim r-1\) 相似,所以从大到小考虑。与 lcp 有关的是夹在这两个后缀排名间 \(h_i\) 的 \(\min\),考虑并查集,每次将 \(h_i=r\) 的后缀 \(sa_i\) 和 \(sa_{i-1}\) 合并,那么只需维护联通块大小,最大值、次大值、最小值、次小值即可。

标签:limits,后缀,int,数组,--,sa,rk
From: https://www.cnblogs.com/xishanmeigao/p/18379006

相关文章

  • 二维数组练习
    //创建一个控制台应用程序,使用二维数组存储火车票信息,输入车次和姓名后,模拟预订火车票功能,代码如下:stringtrain="",destination="",StartTime="";//声明3个字符串:车次,车次信息,出发时间;string[]标题={"车次","出发站-......
  • C/C++语言基础--结构体知识详解(包括:结构体数组、字节对齐、位段等内容)
    本专栏目的更新C/C++的基础语法,包括C++的一些新特性前言C语言地结构体是核心内容之一,他运行自定义数据类型,可以将不同地数据类型当作成一个整体,变成一个数据类型,运用及其广泛欢迎点赞+收藏+关注,本人将会持续更新加粗样式文章目录结构体结构体是什么?结构体的申......
  • C++竞赛初阶L1-14-第六单元-数组(31~33课)543: T456473 年龄与疾病
    题目内容某医院进行一项研究,想知道某项疾病是否与年龄有关。因此对以往的诊断记录进行整理,统计0-18、19-35、36-60、61及以上这四个年龄段的患者人数占总患者人数的比例。输入格式输入共 2 行。第一行包含一个整数 N(0<n≤100),表示总患者人数。第二行包含 N 个......
  • js 数组所有的方法举例版
    1.数组创建Array.of(...):创建一个新的数组实例,其中包含传入的所有元素。点击查看代码console.log(Array.of(1,2,3));//[1,2,3]console.log(Array.of(7));//[7]console.log(Array.of());//[]Array.from(arrayLike,mapFn,thisArg):从类数组或可迭代对......
  • js 数组所有的方法精简版
    1.数组创建Array.of(...):创建一个新的数组实例,其中包含传入的所有元素。Array.from(arrayLike,mapFn,thisArg):从类数组或可迭代对象创建一个新的数组实例。2.访问和修改length:返回或设置数组的长度。at(index):返回数组中指定位置的元素,负数表示从数组末尾倒数......
  • C语言字符数组
    字符数组是一维数组的一种,是当数组中的元素类型为字符型时,称为字符数组。在这里我想讲一下字符数组的结束标志和字符串数组的输入和输出。字符数组的结束标志在C语言中,使用字符数组保存字符串时,系统会自动添加“\0”作为结束符。chararray[]="hello";//初始化字符数组上......
  • 运算符 类定义 Math类的使用 数组的使用
    1.基本的算术运算符5个:+ - * / %都是双目运算符(两个操作数),其中%要求的两个操作数必须为整数。2.自增、自减运算符++ --注意作为前缀和后缀的用法不同.3.表达式计算中的数据类型转换(1)自动类型转换:当参与运算的两个操作数类型不同时,先把低类型的数据转换为高类......
  • P10902 [蓝桥杯 2024 省 C] 回文数组
    P10902[蓝桥杯2024省C]回文数组题解十年OI一场空,不开longlong见祖宗!思路:贪心题目要求将一个随机数组变成一串回文数,可执行的操作如下:相邻两个数同时加\(1\)单个数加\(1\)或减\(1\)由于一个数加\(1\)得到回文数和一个数减\(1\)得到回文数效果一样,我们可以不......
  • 【LeetCode面试150】——3无重复数组的最长子串
    博客昵称:沈小农学编程作者简介:一名在读硕士,定期更新相关算法面试题,欢迎关注小弟!PS:哈喽!各位CSDN的uu们,我是你的小弟沈小农,希望我的文章能帮助到你。欢迎大家在评论区唠嗑指正,觉得好的话别忘了一键三连哦!......
  • 2024-08-24:用go语言,给定一个下标从1开始,包含不同整数的数组 nums,数组长度为 n。 你需
    2024-08-24:用go语言,给定一个下标从1开始,包含不同整数的数组nums,数组长度为n。你需要按照以下规则进行n次操作,将数组nums中的所有元素分配到两个新数组arr1和arr2中:1.首先将nums中第一个元素加入arr1。2.然后将nums中第二个元素加入arr2。3.如果arr1的最后一......