前言:jsoi2017round2day2t1字尾陣列模板題一點都沒看出來。不然就翻盤了
痛定思痛後決定惡補字串。
字尾陣列
全是**上抄來的。
學了一周,終於搞懂一些了。
1.基本定義
字串s;
字尾:從位置i開始到結尾的子串,記作suffix(i)=s[i..len[s]];
字尾陣列sa[1..n]
表示1..n的乙個排列,滿足suffix(sa[i])
即:在所有字尾中排第i的是誰
名次陣列rank[1..n]
表示suffix(i)在字尾中的名次。
即:字尾i排第幾。
所以sa與rank為逆運算。
2.倍增演算法求字尾陣列。
//學過dc3邪教的自行離開。其實我是用字尾自動機構造的。
演算法非常好理解,就是用倍增求出每個字元開始長度為2^k的子字串排序
k==0..log2n上取整, 最後一遍處理時,子串相當於字尾。
**:
1view codevoid
suffix()
23 }
這裡有個小優化:若rank[sa[n]]已經為n時(所有串已經分出大小),就退出。
時間複雜度:o(n log n);不要嘗試跑1e6的構造資料(字元基本相同),常數巨大qaq
3.height陣列(最長公共字首lcp)
學會了構造,就要用字尾陣列搞事情了。
最經典的運用就是height陣列。
定義height[i]=suffix(sa[i])與suffix(sa[i-1])的最長公共字首。
對於suffix(j),suffix(k); rank[j]
他們的最長公共字首為min(height[rank[j]+1]..height[rank[k]]);
毛想想,由於序列是公升序的,那麼陣列的變換是不可逆(若sa[i],sa[i+1]的第j位發生了變化,那麼sa[i],sa[i+1]的第j位(或以前的位)一定也變了)。
那麼問題就是如何快速求出height陣列了。
定義h[i]=height[rank[i]] suffix(i)與前一名的最長公共字首。
舉個例子:
s=abaac
suffix=abaac, baac, aac, ac, c
sa=3,1,4,2,5
rank=2,4,1,3,5
height=0,1,1,0,0
h=1,0,0,1,0
h陣列有以下性質:h[i]>=h[i-1]+1;
證明:設suffix(k)是排在suffix(i-1)前一名的字尾(rank[k]=rank[i-1]-1)
則它們的最長公共字首為h[i-1],
若h[i-1]<2, 那麼顯然成立,當h[i-1]>=2時,s[i-1..i]==s[k..k+1],
且應為k在i-1的前一位,所以k+1排在i的前一位。
所以至少要共享後h[i-1]-1位
voidview codemakeheight()
for (j=sa[rank[i]-1];(j+k<=l)&&(i+k<=l)&&(s[j+k]==s[i+k]);k++);
height[rank[i]]=k;}}
有了height陣列,就可以用rmq求出lcp
例題:[poj2774]求兩個串的最長公共子串(l<100000)
解法:將兩串相連,在中間加乙個沒用到的字元,求出height陣列,在其中找乙個最大的height,且所指的兩個串乙個在空字元前乙個在空字元後。
字尾樹 字尾陣列
在字串處理當中,字尾樹和字尾陣列都是非常有力的工具,其中字尾樹大家了解得比較多,關於字尾陣列則很少見於國內的資料。其實字尾陣列是字尾樹的乙個非 常精巧的替代品,它比字尾樹容易程式設計實現,能夠實現字尾樹的很多功能而時間複雜度也不太遜色,並且,它比字尾樹所占用的空間小很多。可以說,在資訊學競賽 中字尾...
字尾樹 字尾陣列
我們考慮將乙個串的所有字尾插入乙個trie中,得到的trie就是字尾trie。我們可以發現,樹上有分叉或者是字尾節點的點的個數是o l en o len o len 個,這個後面解釋,於是把沒有分支並且不是字尾節點的點壓縮到一起,就變成了字尾樹。不難發現,字尾樹可以表示該字串的所有子串。下面分析一下...
字尾陣列入門,字尾陣列模板整理
我自己懶得寫,就是想寫個部落格儲存下大佬的部落格位址 點這模板題 大佬的模板 include include include include include include include include include include include define inf 0x3f3f3f3f d...