后缀数组(后续)

文章目录

    • **后缀数组 Height**
      • 两个子串最长公共前缀
    • **求Height数组**
      • 比较一个字符串的两个子串的大小关系
      • 不同子串的数目
    • 出现至少k次的子串的最大长度
    • **总结:**
    • 代码:

后缀数组 Height

利用后缀数组快速求出2个后缀的lcp长度
lcp:最长公共前缀
lcp(suf(i),suf(j))
记Height[l] = 排名第(l-1)后缀和排名第l后缀的lcp长度
Height[l] = lcp(suf(SA[l-1]),suf(SA[l]))

l = 后缀suf(i)的排名
r = 后缀suf(j)的排名
结论:

两个子串最长公共前缀

lcp(suf(i),suf(j)) = min(Height[l+1]…Height[r] )
即两个后缀的lcp = 它们排名区间中Height的最小值
维护rmq

求Height数组

暴力求O(N2)

for i =1-Nl =rank[i]j = sa[l-i]k=0while(s[i+k]==s[j+k])k++;Height[l]=k;

suf(k)为s(k…n)构成的子串
SA[1]排序第1的后缀的开始位置
令l =rank[i],r = rank[i-1]
Height[l] = lcp(suf(SA[l-i],suf(i)))
Height[r] = lcp(suf(SA[r-1],suf(i-1)))
结论:
Height[l] >= Height[r]-1
Height[rank[i]] >= Height[rank[i-1]] - 1

利用Height[rank[i]] >= Height[rank[i-1]] - 1优化暴力
复杂度为O(N)

for i =1-Nj = sa[l-i]k=max(0,Height[rank[i-1]-1])while(s[i+k]==s[j+k])k++;Height[l]=k;

之后再用st表来来维护Height的rmq信息

比较一个字符串的两个子串的大小关系

需要比较A=S[a…b]和B=S[c…d]的大小关系
若lcp(a,c)>=min(|A|,|B|),A<B <= => |A| < |B|
否则,A<B <= => rk[a]<rk[b]

不同子串的数目

子串其实就是后缀的前缀,(想办法和后缀扯上关系),所以可以枚举每个后缀,计算前缀总数,再减掉重复
前缀总数其实就是子串个数:n*(n+1)/2
所以答案是:
n*(n+1)/2 - ∑ni=2height[i]

出现至少k次的子串的最大长度

子串可以看做是后缀的前缀,出现k次的子串说明至少有k个后缀的lcp是这个子串,我们对后缀排序,说明至少有连续k个后缀的LCP是这个后缀,既然是连续,那么我们只需要看头和尾就行
所以,求出每相邻k-1个height的最小值,然后求这些最小值的最大值就是我们要的答案
可以用单调队列O(n)解决

总结:

倍增求长度为2k子串的字典序
排序是二元组的基数排序
求SA O(NlogN)
求Height O(N)
求lcp
st表 预处理O(NogN)+单次询问O(1)
P3809 【模板】后缀排序
P4051 【JSOI2007】字符加密
P2852 [USACO06DEC]Milk Patterns G

代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN =1000005;char ch[MAXN], all[MAXN];
int sa[MAXN], rk[MAXN], height[MAXN], tax[MAXN], tp[MAXN], a[MAXN], n, m; 
char str[MAXN];
//rk[i] 第i个后缀的排名; sa[i] 排名为i的后缀位置; height[i] 排名为i的后缀与排名为(i-1)的后缀的LCP
//tax[i] 计数排序辅助数组; tp[i] rk的辅助数组(计数排序中的第二关键字),与sa意义一样。
//a为原串
void RSort() {//rk第一关键字,tp第二关键字。for (int i = 0; i <= m; i ++) tax[i] = 0;for (int i = 1; i <= n; i ++) tax[rk[tp[i]]] ++;for (int i = 1; i <= m; i ++) tax[i] += tax[i-1];for (int i = n; i >= 1; i --) sa[tax[rk[tp[i]]] --] = tp[i]; //确保满足第一关键字的同时,再满足第二关键字的要求
} //计数排序,把新的二元组排序。int cmp(int *f, int x, int y, int w) { return f[x] == f[y] && f[x + w] == f[y + w]; } 
//通过二元组两个下标的比较,确定两个子串是否相同void Suffix() {//safor (int i = 1; i <= n; i ++) rk[i] = a[i], tp[i] = i;m = 127 ,RSort(); //一开始是以单个字符为单位,所以(m = 127)for (int w = 1, p = 1, i; p < n; w += w, m = p) { //把子串长度翻倍,更新rk//w 当前一个子串的长度; m 当前离散后的排名种类数//当前的tp(第二关键字)可直接由上一次的sa的得到for (p = 0, i = n - w + 1; i <= n; i ++) tp[++ p] = i; //长度越界,第二关键字为0for (i = 1; i <= n; i ++) if (sa[i] > w) tp[++ p] = sa[i] - w;//更新sa值,并用tp暂时存下上一轮的rk(用于cmp比较)RSort(), swap(rk, tp), rk[sa[1]] = p = 1;//用已经完成的sa来更新与它互逆的rk,并离散rkfor (i = 2; i <= n; i ++) rk[sa[i]] = cmp(tp, sa[i], sa[i - 1], w) ? p : ++ p;}//离散:把相等的字符串的rk设为相同。//LCPint j, k = 0;for(int i = 1; i <= n; height[rk[i ++]] = k) for( k = k ? k - 1 : k, j = sa[rk[i] - 1]; a[i + k] == a[j + k]; ++ k);//这个知道原理后就比较好理解程序
}void Init() {scanf("%s", str);n = strlen(str);for (int i = 0; i < n; i ++) a[i + 1] = str[i];
}int main() {Init();Suffix();int ans = height[2];for (int i = 3; i <= n; i ++) ans += max(height[i] - height[i - 1], 0);for(int i=1;i<=n;i++)cout<<sa[i]<<" ";puts("");
//    printf("%d\n", ans);    
} 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/319168.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

codeforces1472 G. Moving to the Capital

G. Moving to the Capital 先bfs一边&#xff0c;求出距1号点的最短路用数组d1[]记录&#xff0c;求的过程中如果当前点t遍历到之前遍历过的点j意味着这条边就是能够拉近与1号点距离的边&#xff08;横向边或者后向边&#xff09;那么就用d1[j]更新d2[t]&#xff0c;d2[]表示最…

P3793-由乃救爷爷【分块,ST表】

正题 题目链接:https://www.luogu.com.cn/problem/P3793 题目大意 给出nnn个数字的一个序列mmm次询问区间最大值 保证数据随机 1≤n,m≤21071\leq n,m\leq 2\times 10^71≤n,m≤2107 解题思路 使用STSTST表可以做到O(1)O(1)O(1)询问&#xff0c;但是预处理的时空复杂度都是…

【DP】Mod Mod Mod(CF889E)

正题 CF889E luogu 题目大意 给你 n 个数&#xff0c;让你选择一个X&#xff0c;使得 ∑i1nXmoda1moda2...modai\sum_{i1}^nX\mod a_1\mod a_2...\mod a_i∑i1n​Xmoda1​moda2​...modai​ 最大 解题思路 可以发现必定存在一个 i &#xff0c;使得当前点贡献为 aia_iai​&a…

老张 .NetCore与Vue 框架学习

缘起作为一个.Net攻城狮已经4年有余了&#xff0c;一直不温不火&#xff0c;正好近来项目不是很忙&#xff0c;闲得无聊&#xff0c;搞一搞新技术&#xff0c;一方面是打发无聊的时间&#xff0c;一方面也是督促自己该学习辣&#xff01;身边的大神都转行的转行&#xff0c;加薪…

【平衡规划】Arithmetic Operations(CF1654E)

正题 CF1654E luogu 正题 给你一个正整数序列&#xff0c;你可以让一个位置变成任意整数&#xff0c;问你最少修改多少个数&#xff0c;能使得其成为等差序列 解题思路 考虑根号分治 对于公差小于 n\sqrt{n}n​ 的&#xff0c;直接枚举公差&#xff0c;然后枚举所有点&…

P1251-餐巾计划问题【费用流】

正题 题目链接:https://www.luogu.com.cn/problem/P1251 题目大意 NNN天&#xff0c;第iii天需要aia_iai​个餐巾。 每个餐巾价格为ppp&#xff0c;使用完后有两种清洗方法 清洗mmm天&#xff0c;费用为fff清洗nnn天&#xff0c;费用为sss 求满足所有需求的最小花费 1≤N≤…

J. Spy(多重匹配KM算法)

J. Spy 随机打&#xff0c;最后答案乘n&#xff0c;因为我方等概率的遇见敌人&#xff0c;相当于与n个敌人都打一遍&#xff0c;然后贡献累加作为匹配边权 bfs版本的KM #include<cstdio> #include<cstring> #include<iostream> #include<algorithm>…

2018年10月28日宁波dotnet社区活动回顾及下次活动预告

离上次活动&#xff0c;有半年了&#xff0c;汗。之后尽量保证每月一次&#xff0c;以组织为主&#xff0c;多邀请嘉宾来分享。本次活动不足之处人手不足&#xff1a;由于活动组织事项受限于人手&#xff08;目前就我一个&#xff0c;这次活动前后我又应邀给大红鹰学院应届生介…

[JSOI2007]字符加密

题目描述 喜欢钻研问题的JS 同学&#xff0c;最近又迷上了对加密方法的思考。一天&#xff0c;他突然想出了一种他认为是终极的加密办法&#xff1a;把需要加密的信息排成一圈&#xff0c;显然&#xff0c;它们有很多种不同的读法。 例如‘JSOI07’&#xff0c;可以读作&…

【状压DP】滚榜(P7519)

正题 P7519 题目大意 n个队伍&#xff0c;排名先按分数排序再按编号排序&#xff0c;每个队伍有一个初始分数 aia_iai​&#xff0c;和一个附加分数 bib_ibi​ 对于一个合法的 bib_ibi​ 序列&#xff0c;按 bib_ibi​ 大小排序&#xff0c;从小到大把每个 bib_ibi​ 加进对…

P4480-[BJWC2018]餐巾计划问题【三分,贪心】

正题 题目链接:https://www.luogu.com.cn/problem/P4480 题目大意 nnn天&#xff0c;第iii天需要aia_iai​个餐巾。 每个餐巾价格为ppp&#xff0c;使用完后有两种清洗方法 清洗m1m_1m1​天&#xff0c;费用为c1c_1c1​清洗m2m_2m2​天&#xff0c;费用为c2c_2c2​ 求满足所…

BotSharp v0.2 发布, 支持微信智能回复

BotSharp v0.2 主要是针对微信的消息平台做整合&#xff0c;让.NET开发者可以轻松的搭建基于NLU自然语言理解的智能回复功能&#xff0c;BotSharp.Channel.Weixin模块负责和微信的公众号平台对接&#xff0c;接收消息通知&#xff0c;并能消息产生智能回复&#xff0c;回复的内…

P2852 [USACO06DEC]Milk Patterns G

题目描述 Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation, he discovered that although he can’t predict the quality of milk from one day to the next, there are some regular patterns in th…

codeforces1467 E. Distinctive Roots in a Tree(树上差分)

E. Distinctive Roots in a Tree 树上差分 如果当前节点u的某一棵子树中的某个节点的值和当前节点相同&#xff0c;那么除了当前节点这一棵子树节点&#xff0c;其他节点&#xff08;其他子树以及u上面的节点&#xff09;一定不满足要求。 如果当前节点子树之外的节点&#x…

【图论】旅行者(P5304)

正题 P5304 题目大意 给你一个有向图以及k个关键点&#xff0c;问你关键点之间最短路距离的最小值 解题思路 考虑两个不同点二进制下必定有一位不同 枚举每一位&#xff0c;把该位为1的作为起点跑最短路&#xff0c;然后对于每个为0的点计算答案&#xff0c;反过来同理 时…

c# 弹性和瞬态故障处理库Polly 学习

关于PollyPolly是一个基于.NET的弹性及瞬态故障处理库,允许开发人员以顺畅及线程安全的方式执行重试(Retry)、断路(Circuit Breaker)、超时(Timeout)、隔离(Bulkhead Isolation)和回退策略(Fallback ).Polly适用于 .NET 4.0, .NET 4.5 和.NET Standard 1.1。以上是官方文档对po…

CF444C-DZY Loves Colors【线段树,set】

正题 题目链接:https://www.luogu.com.cn/problem/CF444C 题目大意 nnn个物品第iii个颜色为iii&#xff0c;权值为000。要求支持mmm次操作 给出l,r,xl,r,xl,r,x&#xff0c;对于所有区间[l,r][l,r][l,r]中的物品&#xff0c;如果颜色为ccc&#xff0c;那么该位置的权值加上∣…

codeforces1473 E.Minimum Path(分层图最短路)

E - Minimum Path 分层图最短路 第一个分层图 第0层就是按照题中给的点连边&#xff0c;从第0层到第1层我们连一条边权是0的边&#xff0c;从第1层到第2层连一条边权是原先边权2倍的边&#xff0c;当然第1层以及第2层之间按照原图连边。 第二个分层图 第0层就是按照题中给的点…

【博弈】取石子游戏(P2599)

正题 P2599 题目大意 给n堆石子&#xff0c;第 i 堆有 aia_iai​ 个石子&#xff0c;每次可以从最左边或者最右边的一堆里面取若干个&#xff0c;两个人轮流取&#xff0c;问先手是否存在必胜策略 解题思路 设 li,jl_{i,j}li,j​ 为在 [i,j][i,j][i,j] 右边添加一堆大小 li,…

2020牛客国庆集训派对day8

牛客网链接 文章目录Easy Chess题意&#xff1a;题解&#xff1a;Easy Problemset题意题解&#xff1a;Shuffle Cards题解&#xff1a;Diff-prime Pairs题意题解&#xff1a;代码&#xff1a;Easy Chess 题意&#xff1a; 通过n步从左下角走到右上角&#xff0c;每次移动都是…