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

后缀数组典题

时间:2023-08-27 16:46:28浏览次数:50  
标签:AA lcp 后缀 hgt 典题 数组 字符串 sa

后缀数组典题

约定:\(sa_i\) 表示将所有后缀排序后第 \(i\) 小的后缀的编号,\(rk_i\) 表示后缀 \(i\) 的排名,\(hgt_i=lcp(sa[i],sa[i-1])\)

[NOI2016] 优秀的拆分

求一个字符串的子串能被拆成 \(AABB\) 形式的方案数,其中 \(A,B\) 均为字符串(\(|S|\leq 300000\))。

  • \(O(n^2)\)

枚举 AA 和 BB 中间的位置,用哈希即可解决,有 95 分的高分。

  • \(O(nlogn)\)

考虑 \(pre_i\) 表示以 i 结尾的能被表示成 AA 形式的子串数量,\(suf_i\) 则表示以 i 开头的。那么有:

\[ans=\sum_{i=1}^{n-1}pre_isum_{i+1} \]

考虑统计 \(pre\)(\(suf\) 同理)。
枚举 A 的长度 \(w\),将序列分块,其中 \(x\ mod\ w==0\) 的 x 是关键点。那么任意一组 AA 必定跨越且仅跨越两个唯一的关键点。那么就可以在相邻两个关键点出统计出所有方案。
枚举相邻两个断点 l 和 r,求出它们的前缀最长公共后缀长度 lcs 和后缀最长公共前缀长度 lcp 之和 len:
表示经过两个断点且开头距离 w 的最长公共子串。
lcp 和 lcs 使用 sa 求出。
如果 \(len<w\) ,说明没有同时经过这两个断点的 AA 串。
\(f_{r+lcp−(lcp+lcs−1)→r+lcp−1}+1\)。这个区间修改可以方便的用差分解决。
如下图,即两条紫线以及之间的子串为 AA 串:

时间复杂度 \(O(n+n/2+n/3+...)\),是个调和级数,所以为 \(O(nlogn)\)
code

[NOI2015]品酒大会

定义两杯酒 p,q 的最大相似值为以 p 开头的后缀和以 q 开头的后缀的 lcp。注意两杯酒如果最大相似值为 r,那么它们的相似值还可以是 [0,r-1]。每杯酒都有一个美味值 \(a_i\),两杯酒调兑之后的美味值为 \(a_i \times a_j\)。
回答选择 \(2\) 杯“\(r\)相似”的酒调兑的数量可以得到的美味度的最大值。

观察到当给相似值单调递减的时候,满足条件的区间个数总是越来越少,而新区间都是两个或多个原区间相连所得,且新区间中不包含在原区间内的部分的 \(hgt\) 值都为减少到的这个值。我们只需要维护一个并查集,每次合并相邻的两个区间,并维护统计信息即可。
code

[AHOI2013]差异

给定一个长度为 \(n\) 的字符串 \(S\),令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀。求

\[\displaystyle \sum_{1\leqslant i<j\leqslant n}\operatorname{len}(T_i)+\operatorname{len}(T_j)-2\times\operatorname{lcp}(T_i,T_j) \]

其中,\(\text{len}(a)\) 表示字符串 \(a\) 的长度,\(\text{lcp}(a,b)\) 表示字符串 \(a\) 和字符串 \(b\) 的最长公共前缀。

被加数的前两项很好处理,为 n(n-1)(n+1)/2(每个后缀都出现了 n-1 次,后缀总长是 n(n+1)/2),关键是最后一项,即后缀的两两 LCP。
我们知道 \(lcp(i,j)=k\) 等价于 \(\min\{height[i+1..j]\}=k\)。所以,可以把 \(lcp(i,j)\) 记作 \(\min\{x|i+1\le x\le j, height[x]=lcp(i,j)\}\) 对答案的贡献。
考虑每个位置对答案的贡献是哪些后缀的 LCP,其实就是从它开始向左若干个连续的 hgt 大于它的后缀中选一个,再从向右若干个连续的 hgt 不小于它的后缀中选一个。这个东西可以用单调栈计算。前面的大于和不小于是为了保证 hgt 权值相等时不会被记重复。
code

标签:AA,lcp,后缀,hgt,典题,数组,字符串,sa
From: https://www.cnblogs.com/xu2006/p/17658666.html

相关文章

  • 多行多列合并成一列内存数组的结果
    问题:多行多列合并成一列内存数组的结果函数公式解决:{=PHONETIC(OFFSET(A1:E1,ROW(1:23)-1,))}用Offset函数生成一个多维引用,每个平面分别是A:E表的每一行。利用Phonetic函数将每个平面里的内容进行合并。此公式的缺陷在于被合并的内容只能是文本,如果数据源中包含数值、日......
  • flutter中通过遍历一个数组,给每个元素添加一个开关按钮怎么写
    要通过遍历一个数组给每个元素添加一个开关按钮,你可以使用ListView.builder来构建一个包含开关按钮的列表。下面是一个示例,展示了如何遍历一个数组并为每个元素添加一个开关按钮:List<bool>switchValues=List.generate(5,(index)=>false);ListView.builder(itemCount:sw......
  • 【LeetCode动态规划#17】知道秘密的人,维护多个dp数组
    知道秘密的人数在第1天,有一个人发现了一个秘密。给你一个整数delay,表示每个人会在发现秘密后的delay天之后,每天给一个新的人分享秘密。同时给你一个整数forget,表示每个人在发现秘密forget天之后会忘记这个秘密。一个人不能在忘记秘密那一天及之后的日子里分享......
  • .bat批处理(十):从路径字符串中截取盘符、文件名、后缀名等信息
    文章目录前言`%~dp0`的含义扩展字符串从字符串中截取路径、文件名脚本传参for语法扩展总结 前言又是实际开发中的问题,想要截取一个文件路径中的盘符、文件名等信息,第一反应是正则表达式?或者是split函数?这些往往都是“高级”语言中才会有的实现方法,对于批处......
  • 剑指Offer 21. 调整数组顺序使奇数位于偶数前面
    题目链接:剑指Offer21.调整数组顺序使奇数位于偶数前面题目描述:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数在数组的前半部分,所有偶数在数组的后半部分。解法思路:一、快慢指针法:快指针遍历整个数组,当遇到奇数时,将当前数与慢指针所指的数交换,最终......
  • 【树状数组】牛客练习赛52 B.Galahad
    【树状数组】牛客练习赛52B.Galahad题目链接:https://ac.nowcoder.com/acm/contest/1084/B题意多组询问,计算区间和,但相同的数只能被计算一次。题解离线处理询问,按右端点排序。对于相同的数字,我们只能选一个加入到区间和中,我们是枚举右端点,所以选择最靠近右端点左边的数字最......
  • 大厂算法题每日总结(绳子最大能盖的数组节点)
    //绳子最大能盖的数组节点publicstaticvoidmain(String[]args){int[]arr={1,4,7,9,60};System.out.println(maxPoint2(arr,50));}publicstaticintmaxPoint(int[]arr,intL){//L是绳子的长度 intres=1; for(inti=0;i<arr.length;i++){ intnearest=n......
  • LeetCode-26. 删除有序数组中的重复项(Java)
    这是我在51CTO博客开启的写作之路,第一次正式写博客记录我在LeetCode的刷题日,希望能帮助更多的小伙伴攻面自己心仪的公司offer。如下对于 LeetCode-26. 删除有序数组中的重复项,进行全面解析并小结解题思路,同学们请参考:1.题目描述给你一个 升序排列 的数组 nums ,请你 原地 删......
  • 代码随想录算法训练营第二十三天| 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜
     669. 修剪二叉搜索树    卡哥建议:这道题目比较难,比 添加增加和删除节点难的多,建议先看视频理解。   题目链接/文章讲解:https://programmercarl.com/0669.%E4%BF%AE%E5%89%AA%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html   视频讲解:https://www.......
  • 树状数组进阶
    出去集训讲了一些有关树状数组的NB东西,然后模拟赛考了一个二维树状数组的板子,自己差点没推出来柿子,所以简单写写。参考博客:《树状数组进阶》-Alex_wei树状数组二分树状数组二分,本质上其实应该是树状数组倍增,它是基于倍增的思想实现的。算法流程树状数组二分解决的问题是......