字串系列 SA

2021-09-26 10:44:19 字數 3453 閱讀 9363

高一還不會sa就退役吧

uoj#35. 字尾排序

這是一道模板題。

讀入乙個長度為 n

nn 的由小寫英文本母組成的字串,請把這個字串的所有非空字尾按字典序從小到大排序,然後按順序輸出字尾的第乙個字元在原串中的位置。位置編號為 1

11 到 nnn。

除此之外為了進一步證明你確實有給字尾排序的超能力,請另外輸出 n−1

n - 1

n−1 個整數分別表示排序後相鄰字尾的最長公共字首的長度。

輸入格式

一行乙個長度為 n

nn 的僅包含小寫英文本母的字串。

輸出格式

第一行 n

nn 個整數,第 i

ii 個整數表示排名為 i

ii 的字尾的第乙個字元在原串中的位置。

第二行 n−1

n - 1

n−1 個整數,第 i

ii 個整數表示排名為 i

ii 和排名為 i+1

i + 1

i+1 的字尾的最長公共字首的長度。

樣例一input

ababa

output

5 3 1 4 2

1 3 0 2

explanation

排序後結果為:

aaba

ababa

bababa

限制與約定

1 ≤n

≤105

1 \leq n \leq 10^5

1≤n≤10

5時間限制:1

s1\texttt

1s空間限制:256

mb256\texttt

256mb

乙個卵用並不大的東西

sa能做的sam基本都能做,除了o(1)求字尾的lcp

但有些題就是要這麼搞也沒辦法

一些定義:

st:字串

rank[i]:st[i…n]的字典序排名(顯然各不相同)

sa[i]:排名為i的首字母出現位置(rank的逆陣列),即sa[rank[i]]=i

hi[i](即height):st[sa[i-1]…n]和st[sa[i]…n]的lcp長度,hi[i]=h[sa[i]]

h[i]:st[sa[rank[i]-1]…n]和st[i…n]的lcp長度,h[i]=hi[rank[i]]

h[i]即表示以i為結尾的字尾和i排名的上一位的lcp長度

首先是rank的求法

暴力肯定布星,考慮倍增求rank

每次把相鄰的長度為2k段兩段的rank,用二維桶排來求出新的rank(可重,但最終一定不重)

具體:先排個位,再排十位,因為鄰接表的性質,所以要反著提

直接求height不方便,所以引入了h陣列

h陣列有乙個非常顯然且重要的性質:

證明:

顯然h[i]至少為h[i-1]刪掉i-1,即至少為h[i-1]-1

簡單又自然

有了這個性質後就可以線性求出h陣列,然後可以求出height

(有可能sa[rank[i]-1]>i,所以兩個都不能超出邊界)

可以利用height的性質來搞事

st[sa[i]…n]與st[sa[j]…n]的lcp=min(height[i+1…j])

證明:設st[sa[i]…n]與st[sa[j]…n]的lcp長度為x,則x≥min(height[i+1…j])

若x>min(height[i+1…j]),則與字典序連續相違背,所以x≤min(height[i+1…j])

綜上,x=min(height[i+1…j])

對應到原串中,st[i…n]和st[j…n]的lcp長度為min(height[rank[i]+1…rank[j]])(rank[i]然而這題並沒有用到這個性質

以後再填坑

#include

#include

#include

#include

#include

#define fo(a,b,c) for (a=b; a<=c; a++)

#define fd(a,b,c) for (a=b; a>=c; a--)

#define max(a,b) (a>b?a:b)

#define min(a,b) (ausing

namespace std;

int n,i,j,k,l,len;

int a[

100001];

int pre[

100001];

int ls[

100001];

int st[

100001];

int h[

100001];

//h[i]=hi[rank[i]]

int hi[

100001];

//the lcp of sa[i-1] and sa[i] hi[i]=h[sa[i]]

int rank[

200001];

int sa[

200001];

int rank[

200001];

int bz[26]

;char ch;

intmain()

fo(i,0,

25)bz[i]

+=bz[i-1]

;fo(i,1

,n) rank[i]

=bz[st[i]];

k=1;

while

(k<=n)

l=n;

fd(i,n,0)

}fo(i,1

,n) l=n;

fd(i,n,0)

} j=0;

fo(i,

1,n)

rank[i]

=rank[i];fo

(i,1

,n)

k+=k;}

fo(i,

1,n)

sa[rank[i]

]=i;

fo(i,

1,n)

if(rank[i]

>1)

fo(i,

2,n)

hi[i]

=h[sa[i]];

fo(i,

1,n)

printf

("%d "

,sa[i]);

printf

("\n");

fo(i,

2,n)

printf

("%d "

,hi[i]);

printf

("\n");

}

字串「最」系列

最近練手,整理了乙個 最 系列的主題,這些題目有點繞,個別的還有別名 詳見博文 混在一塊比較亂,就索性放在一起做了個整理,區別的時候要注意子串行與子串的不同,前者不要求連續,後者要求連續 由於大部分跟dp有關,而且一些題目還可以漸進尋求多種解法,可以用來做不錯的練手。下面是這些問題的博文目錄 1 最...

字串系列 word search

題目 已知 乙個二維字元矩陣,乙個單詞 輸出 該單詞是否可以從二維矩陣中拼接出來?拼接規則 從矩陣的某一行的某個字母開始,持續向臨近的字元擴充套件 向上,向下,向左,向右 直至拼接出該單詞。若可以拼出,則輸出false,若拼不出,則輸出false 例如 a,b,c,d,e e,f,g,h,u a,b...

字串dp系列

647.回文子串 給定乙個字串,你的任務是計算這個字串中有多少個回文子串。具有不同開始位置或結束位置的子串,即使是由相同的字元組成,也會被計為是不同的子串。示例 1 輸入 abc 輸出 3 解釋 三個回文子串 a b c 示例 2 輸入 aaa 輸出 6 說明 6個回文子串 a a a aa aa ...