最近系統地學習了一下sa,就演算法本身並不是十分複雜,但關係到字尾陣列的題型卻很多,於是打算整理一下。
計算字串sa通常有倍增和dc3兩種做法,一般選擇倍增,因為常數小且寫起來方便一些。
1. 不可重疊最長重複子串(poj1743)
分析:題目並不是裸的不可重疊最長重複子串問題,需要對於問題進行一些修正,考慮相鄰兩位之間的差值,再進行負數修正,就可以轉化到這樣的題型。
在字尾陣列的很多問題中,height陣列具有很好的性質,由於height陣列是表示,相鄰排名的字尾的最長字首長度,而這道題相當於求一對相同的字首,不過對於字首有不相交的性質。
首先我們二分答案k
kk,如果有一段連續字尾的height都大於k
kk,說明這些字尾具有相同的字首且長度大於k
kk,那麼我們只需要這些字尾中sasa
sa差值大於k,顯然有兩個長度大於k
kk的子串。
(因為如果兩個位置的sa差值大於k
kk,說明他們之間相隔距離大於k
kk,自然字首不會重疊)
//#include
//#include
//#include
//#include
//#include
//#include
//#include
#include
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using
namespace std;
int_read()
const
int maxn =
22222
;int wa[maxn]
, wb[maxn]
, wv[maxn]
, _sum[maxn]
;int
cmp(
int*r ,
int a ,
int b ,
int l )
voidda(
int*r ,
int*sa ,
int n ,
int m )
return;}
int rank[maxn]
, height[maxn]
;void
calch
(int
*r ,
int*sa ,
int n )
return;}
bool
check
(int n ,
int*sa ,
int k )
else
}return0;
}int r[maxn]
, sa[maxn]
;int
main()
r[n]=0
;da( r , sa , n +1,
200)
;calch
( r , sa , n )
;int l =
1, r = n;
while
( l <= r )
if( r >=
4) cout << r +
1<< endl;
else cout <<
0<< endl;
}return0;
}
此題作為sa的模板題
2. 可重疊的k次最長重複子串(poj3261)
分析:這個和上面一題做法相似,同樣是二分答案ans,每次判斷是否存在k個連續字尾滿足height值不小於ans。
3. 不相同的子串的個數(spoj694)
分析:對於任意子串來講,其都可以看做某個字尾的字首,那麼我們需要統計所有不同字首的個數,對於字尾suf
fix(
sa[i
])
suffix(sa[i])
suffix
(sa[
i])來講,對於全部的貢獻為n−s
a[i]
+1
n-sa[i]+1
n−sa[i
]+1,同時需要去掉與sa[
i−1]
sa[i - 1]
sa[i−1
]有交集的hei
ght[
i]
height[i]
height
[i]個字首,所以直接統計出答案為n∗(
n+1)
/2−σ
(hei
ght[
i]
)n*(n+1)/2-\sigma(height[i])
n∗(n+1
)/2−
σ(he
ight
[i])
.
//#include
//#include
//#include
//#include
//#include
//#include
//#include
#include
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using
namespace std;
int_read()
const
int maxn =
55000
;int wa[maxn]
, wb[maxn]
, wv[maxn]
, _sum[maxn]
;int
cmp(
int*r ,
int a ,
int b ,
int l )
voidda(
int*r ,
int*sa ,
int n ,
int m )
return;}
int rk[maxn]
, height[maxn]
;void
calch
(int
*r ,
int*sa ,
int n )
return;}
int r[maxn]
, sa[maxn]
;typedef
long
long ll;
intmain()
cout << ans << endl;
}return0;
}
以上是關於單個字串有關sa的一些典型例題,下面會做一些多字串的問題。 Suffix Array 字尾陣列
顧名思義,suffixarray 以下有時簡稱sa 和字串的字尾有關。字尾 字串中某個位置一直到結尾的子串。sa中討論包括了原串和空串 所以共有len 1個字尾。字尾陣列 字串的所有字尾組成的按字典序從小到大排好的陣列。由於sa中記錄的都是字串的字尾,所以sa只需要記錄其表示的字尾的起始位置。由於比...
字尾陣列(Suffix Array)
字尾陣列是處理字串的有力工具。sa儲存乙個字串按字典序排列的字尾,如圖 rank陣列儲存字尾i的名次,就是把sa反過來,上圖中 rank 1 2,rank 2 8 height陣列儲存相鄰兩個sa字尾之間公共字首的長度,如圖 思路 用倍增的方法對每個字元開始的長度為2 k2 k 2k子字串進行排序,...
字尾陣列suffix array
倍增演算法,時間複雜度o nlogn sa從小到大儲存相對大小的下標 理解lsd,x陣列,sa陣列 char s maxn int sa maxn t maxn t2 maxn c maxn n void build sa int m void build sa int m int cmp suff...