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

后缀数组

时间:2023-11-01 20:24:44浏览次数:33  
标签:tmp cnt 后缀 int 数组 sa rk

后缀数组

以前学了,虽然写了板子,但是好像没学懂,所以重学一遍,随便做了几道板题。

定义

\(sa_i\) :排名第 \(i\) 的后缀是哪一个。

\(rk_i\):第 \(i\) 个后缀的排名。

做法

主要是倍增,每一个后缀初始长度为 \(1\),然后倍增长度扩展,维护每一轮的排序结果。

让一个长度为 \(2^i\) 的串被长度为两个 \(2^{i-1}\) 的串拼出来。

若长度不足,则后面的串就当是 \(0\),然后拼起来之后的排序就是相当于对两个串 \(2^{i-1}\) 进行一个双关键字排序。

可以直接用 \(rk\) 数组代表两个串,设长度为 \(k\),就是对二元组 \((rk_{sa_i},rk_{sa_i+k})\) 进行排序。

直接用 \(sort\) 可以做到 \(O(nlog^2n)\)。

int cmp(int x,int y)
{
    if(rk[x] != rk[y]) return rk[x] < rk[y] ;
    int i = x+p>n?0:x+p ;
    int j = y+p>n?0:y+p ;
    return rk[i] < rk[j] ;
}
void Init()
{
    FOR(i,1,n,1) sa[i] = i,rk[i] = a[i] ;
    FOR(j,1,n,j)
    {
        p = j,sort(sa+1,sa+1+n,cmp) ;
        FOR(i,1,n,1) tmp[sa[i]] = tmp[sa[i-1]]+cmp(sa[i-1],sa[i]) ;
        FOR(i,1,n,1) rk[i] = tmp[i] ;
    }
}

然后 \(sort\) 可以用基数排序优化掉。
简单地说就是先对第二关键字进行计数排序,然后再对第一关键字进行计数排序。
然后用 \(vector\) 常数很大,你只要记一个长度,然后就可以压到一个数组里面了。

    int m = N-3 ;
    FOR(i,1,n,1) sa[i] = i,rk[i] = s[i] ;
    FOR(k,1,n,k)
    {
        me(cnt,0) ; int top = 0 ;
        FOR(i,1,n,1) ++cnt[rk[sa[i]+k]] ;
        FOR(i,1,m,1) cnt[i] += cnt[i-1] ;
        ROF(i,n,1,1) tmp[cnt[rk[sa[i]+k]]--] = sa[i] ;
        me(cnt,0) ;
        FOR(i,1,n,1) ++cnt[rk[tmp[i]]] ;
        FOR(i,1,m,1) cnt[i] += cnt[i-1] ;
        ROF(i,n,1,1) sa[cnt[rk[tmp[i]]]--] = tmp[i] ;
        FOR(i,1,n,1) top += make_pair(rk[sa[i-1]],rk[sa[i-1]+k])!=make_pair(rk[sa[i]],rk[sa[i]+k]),tmp[sa[i]] = top ;
        FOR(i,1,n,1) rk[i] = tmp[i] ;
    }

Hight

\(Hight_i\) :表示的是 \(sa_i\) 和 \(sa_{i-1}\) 的 \(LCP\)。

这东西可以和区间 \(min\) 结合起来,很好用,证不会证,但是很好背。

    int k = 0 ;
    FOR(i,1,n,1)
    {
        if(k) --k ; int j = sa[rk[i]-1] ;
        while(s[i+k] == s[j+k]) ++k ; hi[rk[i]] = k ;
    }

T

P4051 [JSOI2007] 字符加密

Sol

比较简单的题,显然就是对所有的环形字符串进行后缀排序。
将字符串复制一遍,然后就是求跨过的子串的排序。
容易发现全部加上一段后缀不影响,所以直接后缀排序,然后扫 \(sa\) 数组就行了。

P2852 [USACO06DEC] Milk Patterns G

Sol

这道题要用到 \(Hight\) 数组。
由于是后缀的 \(Lcp\),显然这些 \(Lcp\) 是没有完全重合的,也就是说不会算重。
算出 \(Hight\) 数组之后,求出所有长度为 \(k-1\) 的区间的 \(Hight\) 最小值的最大值就好了。

P4248 [AHOI2013] 差异

Sol

题目已经给得很裸了。
显然前面那一坨加的是定值,我们只需要求后面那一坨就好了。
两个后缀的 \(Lcp\) 是他们 \(sa\) 之间的 \(Hight\) 的最小值。
所以对每一个 \(Hight\) 求出是最小值的区间就好了。
值得注意的是,单调栈左边取等,右边不取等,这样就不会算重。

标签:tmp,cnt,后缀,int,数组,sa,rk
From: https://www.cnblogs.com/snow-panther/p/17804011.html

相关文章

  • js 判断数组对象中是否含有重复的值
    //判断对象数组是否有相同属性相同:true\不相同:falsehasFun(array){returnarray.some((item,index)=>{return(array.findIndex((v,i)=>{return(i!==index&&JSON.stringify(v.item......
  • 88. 合并两个有序数组
    描述给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为......
  • 代码 测试用例 测试用例 测试结果 26. 删除有序数组中的重复项
    给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通......
  • 如何将内容添加到数组中?
    内容来自DOChttps://q.houxu6.top/?s=如何将内容添加到数组中?在JavaScript中,如何将一个对象(如字符串或数字)添加到数组中?使用Array.prototype.push方法将值添加到数组的末尾://初始化数组vararr=["Hi","Hello","Bonjour"];//在数组末尾添加新值arr.push(......
  • c# 将十进制数字转换成字节数组
    //将十进制数字转换成字节数组//由数字创建字节数组publicstaticbyte[]DecimalToByteArray(decimalsrc){//创建内存流MemoryStream,stream作为存放二进制数据的缓存using(MemoryStreamstream=newMemoryStream())......
  • 无涯教程-C语言 - 数组(Array)
    数组是一种数据结构,可以存储相同类型的元素的固定大小的顺序集合。所有数组均包含连续的内存位置,最低地址对应于第一个元素,最高地址对应于最后一个元素。声明数组要在C中声明数组,程序员可以指定元素的类型和数组所需的元素数量,如下所示-typearrayName[arraySize];这称为......
  • 数组,list,字符串的一些转换
    //list转数组Long[]ids=updateIds.toArray(newLong[updateIds.size()]) // 数组转listList<String>reasonList=Arrays.asList(perm.trim().split(",")) // String转数组String[]reasons=business.getReason().split(",") //数组转字符串需要引⼊......
  • 05数据结构(栈、队列、数组、链表)
    数据结构一、什么是数据结构计算机底层存储、组织数据的方式。是指数据相互之间是以什么方式排列在一起的。数据结构是为了更加方便的管理和使用数据,需要结合具体的业务场景来进行选择。一般情况下,精心选择的数据结构可以带来更高的运行或者存储效率。如何学习数据结构:每......
  • 后缀数组 学习笔记
    后缀数组学习笔记定义我们定义后缀数组\(Sa\)中的元素\(Sa_i\)为,字典序排名为\(i\)的后缀所在的位置。我们定义排名数组\(Rank\)中的元素\(Rank_i\)为,在位置\(i\)的后缀的排名。求解后缀数组首先\(O(n^2logn)\)的解法很显然,直接排序。那么有一个利用倍增的思......
  • 整型数组按照字典序排序
    整型数组按照字典序排序输入...0,1,2,3,5,7,8,1001,109...输出...0,1,10,1001,2,3,5,7,8Collections.sort(list,newComparator<Integer>(){@Overridepublicintcompare(Integero1,Integero2){StringA=o1+"";StringB=......