• 后缀数组复习笔记


    好久之前就打算写了,结果咕到现在

    倍增求 SA

    考虑使用类似计数排序的思想来求 SA,对每个位置 \(i\) 有双关键字 \((rk[i],rk[i+w])\) 优先按照第一关键字排序

    char s[np];
    int n,id[np * 2],bac[np];
    int height[np];
    int rk[np * 2],sa[np * 2],oldrk[np * 2];
    // rk[i] 表示后缀 i 的排名,sa[i] 表示排名为 i 的后缀是谁
    // oldrk[i] 表示上一轮 rk
    inline void getsa()
    {
    	int alp=max(256,n);
    	for(int i=1;i <= n;i ++) bac[rk[i] = s[i]] ++;
    	for(int i=1;i <= alp;i ++) bac[i] += bac[i-1];
    	for(int i=n;i >= 1;i --) sa[bac[rk[i]]--] = i;
    	for(int w=1;w < n;w <<= 1) // (i,i+2^w)]
    	{
    		for(int i=0;i <= alp; i++) bac[i] = 0,id[i] = i;
    		for(int i=1;i <= n;i ++) bac[rk[id[i] + w]] ++;//排第二关键字
    		for(int i=1;i <= alp;i++) bac[i] += bac[i-1];
    		for(int i=n;i >= 1;i --) sa[bac[rk[id[i] + w]]--] = id[i];
    		
    		for(int i=0;i <= alp;i ++) bac[i] = 0,id[i] = sa[i];// 按照上一维的排名排第一维
    		for(int i=1;i <= n;i ++) bac[rk[id[i]]] ++;
    		for(int i=1;i <= alp;i ++) bac[i] += bac[i-1];
    		for(int i=n;i >= 1;i --) sa[bac[rk[id[i]]]--] = id[i];
    		
    		for(int i=1;i <= n;i ++) oldrk[i] = rk[i];
    		for(int i=1,p=0;i <= n;i ++)
    		{
    			if(oldrk[sa[i]] == oldrk[sa[i - 1]] && oldrk[sa[i] + w] == oldrk[sa[i-1] + w])
    			rk[sa[i]] = p;// 本质相同
    			else rk[sa[i]] = ++p;// 
    		}
    	}
     }
    

    求 height 数组

    规定:
    \(\operatorname{height}_i\) 表示 \(i-1\)\(i\) 的两后缀的最长公共前缀

    \[\operatorname{height}_i = \operatorname{lcp}(sa_{i-1},sa_i) \]

    \(h_i\) 表示后缀 i 和排名在 i 之前一位的后缀最长公共前缀

    \[h_i = \operatorname{height}_{rk_i} = \operatorname{lcp}(sa_{rk_i-1},i) \]

    直接给出结论

    \[\operatorname{lcp}(sa_i,sa_j) = \min\limits_{k=i+1}^j\{\operatorname{height}_k\} \]

    如何求 \(\operatorname{height}\) 数组呢

    再给出结论 \(h_i \geq h_{i-1}-1\)

    给出证明

    对于 \(h_i = \operatorname{lcp}(i,sa_{rk_i-1})\)

    \(u = i,v = sa_{rk_i-1}\)

    对于 \(h_{i-1}\) 来说,设 \(u' = i-1,v' = sa_{rk_{i-1}-1}\)

    不妨设 \(k=h_{i-1}\geq 1\) 对于另一部分结论显然成立

    则有 \(\operatorname{lcp}(u',v')=k\),考虑去掉 \(u'\)\(v'\) 的首字母后分别为 \(x\)\(y\),且有 \(x\)\(y\) 的字典序相对大小不变。显然有 \(\operatorname{lcp}(x,y)=k-1\) 并且 \(x=u=i\)。相当于 \(\operatorname{lcp}(i,y)=k-1\)

    最后有如下关系 \(y\leq v < i\) 根据 LCP lemma 有 \(\operatorname{lcp}(v,i)\geq \operatorname{lcp}(y,i)\)

    证毕

    这条性质可以被称作「不完美单调性」

    inline void getHeight()
    {
    	for(int i=1,k=0;i <= n ;i ++)
    	{
    		if(rk[i] == 1) height[1] = 0;
    		else{
    			if(k > 0) k --;
    			int l=sa[rk[i] - 1];
    			while(l + n <= n && i + k <= n && s[i + k] == s[l + k]) k ++;
    			height[rk[i]] = k;
    		}
    	}
    }
    

    CF1063F

    显然有一个 \(O(n\sqrt n)\) 的优雅做法,但我们要追求 \(\rm polylog\) 做法

    考虑一个dp

    设 dp[i] 表示起始是 i 的最大划分数量。则有这样一个转移

    \[dp[i] = \min_{j>i}(j-i,dp[j]+1,\operatorname{lcp}(s[i:n],s[j:n])) \]

    或者

    \[dp[i] = \min_{j>i}(j-i,dp[j]+1,\operatorname{lcp}(s[i+1:n],s[j:n])) \]

    现在我们手里有了一个 \(O(n^2)\) 的 dp 考虑优化

    经过推理可以发现一个性质 \(dp[i] \leq dp[i+1] + 1\)

    可以观察出这个东西非常像 \(\rm height\) 的数组形式,我们考虑和它类似的维护

    每次都直接继承上一个答案,然后顺序递减枚举即可。

    考虑如何 check 当前 dp 值是否合法

    相当于 dp 值需要同时满足 min 中的三个表达式

    对于 \(\operatorname{lcp}(s[i+1:n],s[j:n])\) 只需要在对应的 \(sa\) 区间上二分左右端点就行。

    对于前两个条件,只需要保证在当前 dp 值下降的时候维护一棵线段树不断向其中插入元素即可,同时维护 dp 最大值。

    link

    P4094

    sa 套路题之一吧算是。

    首先二分答案

    考虑如何 check 是否存在 \(\max\limits_{i=a}^b\operatorname{lcp}(s[i:b],s[c:d]) \geq ans\) 即可

    首先对 sa 建主席树,每次 check 直接在 c 在 sa 的位置上二分左右区间,然后做一个二维数点就行

    sa 经典题了算是

    link

    P4770

    首先有一个和上题一模一样的做法不过复杂度是 \(O(\sum|T|\log^2n)\)

    考虑优化,发现对于 \(T[i-1]\)\(T[i]\) 它们必然有这样一个关系

    \[\operatorname{lcp}(S[l:r],T[i-1])-1\leq\operatorname{lcp}(S[l:r],T[i]) \]

    考虑和 \(h_i\) 一样的证明即可,对于不完全单调性可以使用一个类似 CF1063F 的做法,这样复杂度就被降到 \(O(\sum|T|\log n)\)

    但是由于每次都要在主席树上查询和二分实在是太慢了,并且数组访问并不连续。

  • 相关阅读:
    向多页TABLE中插入数据时,新增行总是在当前页的最后一行
    本地Run Page时报检测到意外的 URL 参数,它将被忽略。
    本地Jdev Run PG报严重: Socket accept failed错误
    手动编译JAVA类
    动态创建OATipBean
    OAF TABLE中第一列添加事件不生效
    QML的Window与ApplicationWindow
    android studio快捷键
    Android Studio报错view is not constrained
    自定义信号
  • 原文地址:https://www.cnblogs.com/-Iris-/p/15557232.html
Copyright © 2020-2023  润新知