首页 > 其他分享 >SA 学习笔记

SA 学习笔记

时间:2024-08-04 22:43:39浏览次数:12  
标签:tmp 后缀 笔记 学习 SA 排序 sa rk

SA 的定义

一个字符串有 \(n\) 个后缀,把 \(n\) 个后缀按字典序排序,得到数组 \(sa\)。\(sa\) 的每一个元素是每个后缀的第一个字符的 index。

\(rk\) 数组代表了原先的每个后缀在排序后的位置。

例如:eaabd,其后缀为 eaabd aabd abd bd d,排序后为 aabd abd bd d eaabd,\(sa = \{2,3,4,5,1\}, rk = \{5,1,2,3,4\}\)。

SA 怎么求

考虑倍增。

初始轮,\(w=1\),把 \(sa\) 按每个字符排序。

接下来的每一轮,\(w \leftarrow w \times 2\),这次的串 \(x\) 应该由上一轮的 \([x,x+w)\) 和 \([x+w,x+2w)\) 两个串拼成。把 \(sa\) 以 \(rk_x\) 为第一关键字,\(rk_{x+w}\) 为第二关键字排序,其中 \(rk\) 为由上一轮的排序的 \(sa\) 得到的 \(rk\)。

时间复杂度 \(O(n \log^2 n)\),如果用基数排序可以做到 \(O(n \log n)\)。

int sa[MAXN], rk[MAXN * 2], tmp[MAXN * 2];
// 因为有 +w,开大一倍防止越界
// 因为在统计这一轮的 rk 时还要用到上一轮的 rk,所以这一轮的 rk 先放在 tmp 里,结束后 copy
void build_SA(string S) {
    rep(i, 1, n)
        sa[i] = i, rk[i] = S[i];
    for (int w = 1; w <= n; w <<= 1) {
        auto cmp = [&](int x, int y) -> bool {
            if (rk[x] == rk[y])
                return rk[x+w] < rk[y+w];
            return rk[x] < rk[y];
        };
        sort(sa+1, sa+n+1, cmp);
        rep(i, 1, n)
            tmp[sa[i]] = tmp[sa[i-1]] + cmp(sa[i-1], sa[i]);
        copy(tmp+1, tmp+n+1, rk+1);
    }
}

SA 其实还有 \(O(n)\) 求法,但是并不实用。

例 1:\(k\) 小表示法

例:P4051 [JSOI2007] 字符加密 给定一个字符串 \(S\),仿照最小表示法问题,求其 \(k\) 小表示法。

解:对 \(S + S\) 求 SA 即可。时间复杂度 \(O(n \log^2 n)\)。

Height 数组

定义:\(h_i = \text{LCP}(sa_i, sa_{i-1})\)。特别地,\(h_1 = 0\)。求出 \(h\)。

可以证明:\(h[rk_i] \ge h[rk_{i-1}] - 1\)。

基于这个引理,我们按 \(rk\) 顺序暴力求出 \(h\),均摊后总复杂度就是 \(O(n)\)。

    int k = 0;
    rep(i, 1, n) {
        int j = sa[rk[i] - 1];
        if (k) k--;
        while (S[i + k] == S[j + k])
            k++;
        h[rk[i]] = k;
    }

例 2:本质不同子串数量

P2408 不同子串个数

对于每一个相同子串,我们都只在它出现的最大后缀中记录它的贡献。

对于每个后缀 \(i\),出现在 \(sa[rk_i + 1]\) 中的前缀不会被记录贡献,而没有出现的则会记录贡献,没被记录贡献的子串数为 \(h[rk_i + 1]\)。

因此,答案为 \(\frac {n (n+1)} 2 - \sum\limits_{i=2}^n h_i\)。不开 long long 见祖宗

标签:tmp,后缀,笔记,学习,SA,排序,sa,rk
From: https://www.cnblogs.com/AugustLight/p/-/SA-Note

相关文章

  • day1-Django笔记
    1.手动创建Django项目(初学则推荐)创建一个python虚拟环境>=3.61.win+r进入终端2.condaenvlist#查看有哪些虚拟环境3.condacreate--namepy36_netpython==3.6#创建一个python环境4.activate虚拟环境名#激活虚拟环境5.condadeactivate#退出虚拟环境安装dja......
  • Python基础算法笔记
    整理自B站视频https://www.bilibili.com/video/BV1uA411N7c5递归1.汉诺塔问题#n个圆盘,从a经过b移动到cdefhanoi(n,a,b,c):ifn>0:#将n-1个圆盘从a经过c移动到bhanoi(n-1,a,c,b)#将最底层的圆盘从a移动到cprint("mov......
  • 动态规划,蒙特卡洛,TD,Qlearing,Sars,DQN,REINFORCE算法对比
    动态规划(DynamicProgramming,DP)通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划的步骤识别子问题:定义问题的递归解法,识别状态和选择。确定DP数组:确定存储子问题解的数据结构,通常是数组或矩阵。确定状态转移方程:找出状态之间的关系,即状态转移方程。......
  • 优化蒙特卡洛算法笔记1
    fromkaiwu_agent.utils.common_funcimportcreate_cls,attachedSampleData=create_cls("SampleData",state=None,action=None,reward=None)ObsData=create_cls("ObsData",feature=None)ActData=create_cls("ActData",ac......
  • 学习笔记第十七天
    1.Shell基本语法    1.注释:以#符号开始,直到行末,用于解释代码或暂时禁用某行代码。    2.命令:如echo、ls等,用于执行系统命令或调用外部程序。    3.控制结构:包括if语句、for循环、while循环等,用于控制脚本的流程。2.创建和执行脚本    1.......
  • 【机器学习】线性回归和逻辑回归的关系以及LinearRegression、LogisticRegression两种
    引言线性回归和逻辑回归是机器学习中两种常用的回归分析方法,它们在应用、性质和目的等方面存在显著差异文章目录引言一、线性回归1.1定义与目的1.2公式与计算1.3应用场景1.4特点与要求二、逻辑回归2.1定义与目的2.2公式与计算2.3应用场景2.4特点与要求三、......
  • 扩散模型在机器学习中的应用及其挑战
    扩散模型在机器学习中的应用及其挑战大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!扩散模型(DiffusionModels)是一类近年来在机器学习领域获得广泛关注的生成模型。这些模型在生成任务中的表现尤为突出,包括图像生成、图像恢复和文本生成等。尽管扩散......
  • 《802.11无线网络权威指南-无线网络导论》-- 读书笔记1
    专业术语发射塔:celltower,指信号发射塔基站,接入点:accesspoint无线数据网络:wirelessdatanetwork基站:basestationauthorization:授权,认证serviceprovider:服务供应商hotspot:热点WAN:广域网络infraredlight:红外线频带:frequencyband带宽:bandwidth,即可供使用的频率......
  • KMP学习笔记
    KMP一种字符串单模匹配算法。原理当模式串\(s\)与文本串\(t\)进行匹配时,容易想到的一种朴素做法就是将模式串的第一位与文本串的每一位进行试配。但是这样效率过低,容易被数据卡成\(O(n^2)\)。KMP单模匹配算法引入了一个失配数组border。定义一个字符串的border为一......
  • QT 笔记
     HTTPSSSL配置下载配置子父对象QTimer*timer=newQTimer;//QTimerinheritsQObjecttimer->inherits("QTimer");//returnstruetimer->inherits("QObject");//returnstruetimer->inherits("QAbstractBut......