字尾陣列小記

2022-05-05 11:57:09 字數 3703 閱讀 9417

\(sa[i]\) 表示第 \(i\) 小的字尾對應原串的位置

\(rk[i]\) 表示第 \(i\) 個字尾的排名

\(x[i]\) 表示第 \(i\) 個字尾的第一關鍵字排名,即當前的 \(rk[i]\)

\(y[i]\) 表示第 \(i\) 小的第二關鍵字對應的第幾個字尾

\(c[i]\) 是乙個計數陣列,用於基數排序用

考慮倍增,每次從 \(2^k\) 轉移到 \(2^\) ,可以發現每個 \(2^\) 串可以表示為兩個 \(2^k\) 的子串,分別對應兩個關鍵字。

用基數排序即可。

複雜度 \(o(nlogn)\)

定義 \(lcp(i,j)\) 表示 \(suf(sa[i])\) 和 \(suf(sa[j])\) 的最長公共字首長度。

顯然有:

考慮乙個強大的結論:

對於任意 \(1\le i< k< j\le n\),均有 \(lcp(i,j)=min(lcp(i,k),lcp(k,j))\)

證明:設 \(p=min(lcp(i,k),lcp(k,j))\) ,則有 \(lcp(i,k)\ge p, lcp(k,j)\ge p\) 。

設 \(suf(sa[i]) = u, suf(sa[k]) = v, suf(sa[j]) = w\) ,

則由 \(lcp\) 定義知 (\(u\) 和 \(v\))、(\(v\) 和 \(w\)) 前 \(p\) 個字元均相等。

因此 \(u\) 和 \(w\) 的前 \(p\) 個字元相等,所以 \(lcp(i,j)\ge p\)

假設 \(lcp(i,j)=q > p\) ,那麼 \(q\ge p + 1\) ,即 \(u[p+1]=w[p+1]\) 。

因為 \(p=min(lcp(i,k),lcp(k,j))\) ,所以 \(u[p+1]≠v[p+1]\) 或 \(v[p+1]≠w[p+1]\)

因為 \(suf(sa[i]),所以 \(u[p+1]=v[p+1]=w[p+1]\)

矛盾,故 \(lcp(i,j)\le p\)

因此 \(lcp(i,j)=p=min(lcp(i,k),lcp(k,j))\) 。

終極結論:

\(lcp(i,j)=min(lcp(k-1,k) | i < k\le j)\)

證明:由 \(lcp\ lemma\) 知 \(lcp(i,j)=min(lcp(i,j-1),lcp(j-1,j))=min(min(lcp(i,j-2),lcp(j-2,j-1)),lcp(j-1,j))=...=min(lcp(k-1,k) | i < k\le j)\)

前面都是鋪墊。

我們設 \(height[i]=lcp(i-1,i)\) (\(1) ,顯然 \(height[1] = 0\)

由 \(lcp\ theorem\) 知 \(lcp(i,j)=min(height[k] | i

那麼,這個 \(height\) 該咋求呢?

繼續定義 \(h[i] = height[rk[i]]\) ,則有 \(height[i] = h[sa[i]]\)

下面來證明乙個最關鍵的定理:\(h[i]\ge h[i-1]-1\) ,即 \(height[rk[i]]\ge height[rk[i-1]] - 1\) 。

也即 \(lcp(rk[i]-1,rk[i])\ge lcp(rk[i-1]-1,rk[i-1])-1\) 。

證明:不妨設第 \(i-1\) 個字串按排名來前面的是第 \(k\) 個字串。

由 \(height\) 定義知第 \(k\) 個字串和第 \(i-1\) 個字串的 \(lcp\) 為 \(height[rk[i-1]]\)

下面我們來討論兩字串間的關係:

那麼第 \(k+1\) 個字串的排名既有可能在 \(i\) 前面,也有可能在 \(i\) 後面。

但沒關係,此時 \(height[rk[i-1]]=0\) ,一定滿足 \(height[rk[i]] \ge height[rk[i-1]] - 1\)

由於第 \(k+1\) 個字串就是第 \(k\) 個字串去掉首字元得到的,第 \(i\) 個字串就是第 \(i-1\) 個字串去掉首字元得到的,所以第 \(k+1\) 個字串和第 \(i\) 個字串的 \(lcp\) 就是 \(height[rk[i-1]]-1\)

注意第 \(k+1\) 個字元不一定是第 \(sa[rk[i]-1]\) 個字串,但是因為第 \(sa[rk[i]-1]\) 個字串和第 \(i\) 個字串的 \(lcp\) 最大,即 \(height[rk[i]]=lcp(rk[i]-1,rk[i])\ge lcp(rk[k+1],rk[i])=height[rk[i-1]]-1\)

綜上所述,可證得 \(h[i]\ge h[i-1]-1\)

貼份**,跑路

// author: wlzhouzhuan

#pragma gcc optimize(2)

#pragma gcc optimize(3)

#include using namespace std;

#define ll long long

#define ull unsigned long long

#define rint register int

#define rep(i, l, r) for (rint i = l; i <= r; i++)

#define per(i, l, r) for (rint i = l; i >= r; i--)

#define mset(s, _) memset(s, _, sizeof(s))

#define pb push_back

#define pii pair #define mp(a, b) make_pair(a, b)

#define debug(x) cerr << #x << " = " << x << '\n';

#define pll pair #define fir first

#define sec second

inline int read()

while (isdigit(op))

return neg * x;

}inline void print(int x)

if (x >= 10) print(x / 10);

putchar(x % 10 + '0');

}const int n = 1000005;

char s[n];

int n, m;

int sa[n], rk[n], x[n], y[n];

int cnt[n];

void sa()

if (p == n) break;

m = p;

} memcpy(rk, x, sizeof(x));

}int height[n], h[n][20], lg[n];

int getheight()

for (rint j = 1; j < 20; j++)

}}int lcp(int l, int r)

int main()

puts("");

lg[1] = 0;

for (rint i = 2; i <= n; i++) lg[i] = lg[i >> 1] + 1;

int l, r;

while (~scanf("%d%d", &l, &r))

return 0;

}

字尾陣列複習小記

字尾陣列,顧名思義就是處理字尾的陣列。例如daabbc的字尾 daabbc,aabbc,abbc,bbc,bc,c六個字尾。定義sa i 為排名第i個的字尾的第乙個字元在原字串中的序號。如上面的sa 1 2,因為字尾從序號2開始的aabbc排第乙個。定義rank i 為序號從i開始的字尾排第幾個。如...

字尾陣列複習小記

定義 suf i 表示以i為開頭的字尾 rank i 表示suf i 的排名,sa i 表示排名為i的字尾 height i 表示sa i 和sa i 1 的lcp h i 表示suf i 和suf sa rank i 1 的lcp sa rank i i,所以只要能求出rank,就可以求sa 倍增...

字尾樹 字尾陣列

在字串處理當中,字尾樹和字尾陣列都是非常有力的工具,其中字尾樹大家了解得比較多,關於字尾陣列則很少見於國內的資料。其實字尾陣列是字尾樹的乙個非 常精巧的替代品,它比字尾樹容易程式設計實現,能夠實現字尾樹的很多功能而時間複雜度也不太遜色,並且,它比字尾樹所占用的空間小很多。可以說,在資訊學競賽 中字尾...