首页 > 其他分享 >后缀数组学习笔记

后缀数组学习笔记

时间:2024-04-17 10:35:00浏览次数:30  
标签:后缀 sum 笔记 height 数组 字符串 sa rk

定义

后缀

从字符串某个位置i到字符串末尾的子串,定义s的第i个字符为第一个元素的后缀为suf(i)。

后缀数组

把s的每一个后缀按照字典序排序,后缀数组sa[i]表示排名为i的后缀的起始位置的下标。rk[i]数组代表起始位置为i的后缀的排名。

rk[]和sa[] 是一一对应关系,互为逆运算,可以相互推导

倍增

倍增法求后缀数组是从字符串的第一个字符开始比较,然后每次倍增比较长度,直到完成。每次都递增两倍,所以总步骤一共只有 \(\log_2 n\) 次,非常高效。

优化

如果字符串很长,包含10000个字符,那么在最后一步,每个数字都有10000位,无法存储与排序。

方法是在每步操作后就对组合数字进行排序,用序号产生一个新数字,再用新数字进行下一步排序。

基数排序即可。

sa2

height数组

大概是SA里最核心,最有用的部分。

\(height[i]\) 表示 \(suf(sa[i])\) 与 \(suf[sa[i -1]]\) 的最长公共前缀(LCP)。

性质:\(height[i] \ge height[rk[i - 1]]-1\) 。

lcp求解:\(lcp(i, j) = \min_{k =rk[i]+1}^{rk[j]} height[k]\)

代码

const int N = 1e6 + 7;
int sa[N], rk[N], c[N], x[N], y[N], height[N];

char s[N];
int n, m;

void get_sa() {
    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);
        num = 1, x[sa[1]] = 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 get_height() {
    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;
    }
}

题目

主要是进行一些做题的记录,所以思路写的比较草,不是很详细。

P4051 [JSOI2007] 字符加密

把原串拼一个在后面,求出sa数组后,如果这个位置在原串里,那输出对应结尾的字符。

UVA1223 Editor

给定文本字符串 \(s\),查找文本字符串 \(s\) 中最长的子字符串,使得子字符串至少出现两次。

对于出现两次的子串,一定是后缀排序后相邻的两个的公共前缀,答案即为对 \(height\) 数组取最大值。

P2408 不同子串个数

不同字串的个数就是所有的字串减去相同的字串个数。总的字串个数为 \(\frac{n(n + 1)}{2}\) 。所有后缀产生的相同的前缀个数为 \(\sum_{1}^{n} height[rk[i]]\),相同的字串个数为 \(\sum_{1}^{n} height[rk[i]]\)。答案为 \(\frac{n(n+1)}{2} - \sum_{1}^{n} height[rk[i]]\)。

CF802I Fake News (hard)

设 \(x\) 为该子串在这之前出现的次数。

\(Ans = \sum_{i = 1}^{n} \sum_{pre(sa_i)} 2\times x + 1 = \sum_{i=1}^{n}\sum_{pre(sa_i)} + 2\times\sum_{i=1}^{n}\sum_{pre(sa_i)}x = \frac{n(n+1)}{2}+\sum_{i=1}^{n} \sum_{pre(sa_i)}x\)

然后单调栈即可。

P3181 [HAOI2016] 找相同字符

把两个字符串中间加一个特殊字符合并在一起,求一遍sa和height数组。答案就是 \(\sum _{sa[i]<n+1<sa[j]} \min _{i\le k \le j} height[k] + \sum_{sa[j]<n+1<sa[i]} \min_{i\le k \le j} height[k]\) 。

P2178 [NOI2015] 品酒大会

好题,学到了。

求有多少对后缀的lcp 大于等于r。发现当限制条件为r的时候height数组一定会被一个小于r的分成若干个块。随着r的变小,块会向外扩,可以理解为并查集操作。

P1117 [NOI2016] 优秀的拆分

记 \(a_i\) 为从1到 \(i\) ,有多少个形如AA。\(b_i\) 为从 \(i\) 到1,有多少个形如BB。\(Ans=\sum_{i=1}^{n-1} a[i]*b[i+1]\)

\(O(n^2)\) 有95 赚麻了/

很厉害题。

挂个题解链https://www.cnblogs.com/acfunction/p/10087144.html

P3975 [TJOI2015] 弦论

给定字符串,求字符串的第 \(k\) 小字串。同时每次给 \(t\) ,若 \(t=0\) 表示不同位置相同子串算一个,否则算作多个。

标签:后缀,sum,笔记,height,数组,字符串,sa,rk
From: https://www.cnblogs.com/wwyyyy/p/18140003

相关文章

  • 《线性代数的本质》笔记(09)
    09-基变换基向量不同,则相同坐标的向量实际上并不是同一个。将新的基向量看作是线性变换,则其列应该是原本的基向量现在的位置。将一个新坐标系下的向量a(x,y)转换到我们的坐标系中:用这个矩阵乘以这个向量。原因:用两组基向量分别表示向量在两个坐标系下的位置,则结果应该是相同的。所......
  • day14_我的Java学习笔记 (常用API、Lambda、常见算法)
    1.常用API1.1Date类【案例】:计算出当前时间往后走1小时121秒之后的时间是多少。1.2SimpleDateFormat【练习】:秒杀活动1.3Calendar2.JDK8新增日期类2.1概述、LocalTime/LocalDate/LocalDateTime2.2Ins......
  • day12_我的Java学习笔记 (package包、权限修饰符_private+缺省+protected+public、fin
    1.包IDEA配置自动导包:2.权限修饰符同一个类中的,【private、缺省、protected、public】都可以访问同一个包中的其他类,【private】不可以访问,【缺省、protected、public】都可以访问不同包下的无关类,【private、缺省、protected】都不可以访问,只有【public......
  • 笔记本电脑上的聊天机器人: 在英特尔 Meteor Lake 上运行 Phi-2
    对应于其强大的能力,大语言模型(LLM)需要强大的算力支撑,而个人计算机上很难满足这一需求。因此,我们别无选择,只能将它们部署至由本地或云端托管的性能强大的定制AI服务器上。为何需要将LLM推理本地化如果我们可以在典配个人计算机上运行最先进的开源LLM会如何?好处简直太......
  • 模型微调-书生浦语大模型实战营学习笔记&大语言模型5
    大语言模型-5.模型微调书生浦语大模型实战营学习笔记-4.模型微调本节对应的视频教程为B站链接。笔记对视频的理论部分进行了整理。大模型的训练过程模型视角这里原视频用的“分类”这个名字,我看到的时候还有点懵......
  • Java 常用笔记
    问题1org.springframework.beans.factory.BeanCreationException:Errorcreatingbeanwithname'jobConfParser'definedinclasspathresource[com/cxytiandi/elasticjob/autoconfigure/JobParserAutoConfiguration.class]:Initializationofbeanfailed;n......
  • 笔记:OpenCV3和Qt5 计算机视觉应用开发(一)
    目标:学习《OpenCV3和Qt5计算机视觉应用开发》,记录总结学习过程。第一章OpenCV和Qt简介开发环境系统版本:Ubuntu16.04.7LTSQt版本:Qt5.9.5OpenCV版本:opencv-3.3.0虚拟机版本:VMware®Workstation16Pro(16.2.2build-19200509)学习总结1,安装Linux开发环境终端运行:sudoapt-get......
  • 笔记:OpenCV3和Qt5 计算机视觉应用开发(二)
    目标:学习《OpenCV3和Qt5计算机视觉应用开发》,记录总结学习过程。第2章创建第一个Qt+OpenCV项目学习总结1,信号与槽机制。2,Qt对象树机制实现自动内存管理。3,问题:程序异常结束。OpenCVError:Unspecifiederror(couldnotfindawriterforthespecifiedextension)inimwrite......
  • 笔记:J1939协议之DM1
    目标:学习SAE1939-73中的DM1,尤其是多包故障的传输规则一、基本概念SAE1939-73即CAN总线J1939协议的应用层-诊断符号缩写的含义DM1诊断信息1,当前故障码DM2诊断信息2,历史故障码DM3诊断信息3,历史故障码的清除/复位DM4诊断信息4,停帧参量DM5诊断信息5,诊断准备就绪DM6诊断信......
  • 笔记;超声波倒车雷达方案分析(一)
    需求:搜集超声波倒车雷达方案,了解基础知识和开发要点。一、基础概念1.1测量原理超声波发送探头向外发送超声波,超声波在向外扩散过程中遇到障碍物会产生反射波,通过接收探头对反射波进行接收,采集发送和接收到超声波的时间差来计算障碍物的距离。常用探头工作频率有40KHz,48KHz以及58......