關於字尾陣列的學習可以參考:字尾陣列學習小記 (模板) - whyorwhnt的專欄
個人經驗:對單個字串問題求個數需要列舉,求長度可以利用二分
公共子串:如果字串l同時出現在字串a和字串b中,則稱字串l是字串a和字串b的公共子串。
與子串行不同的是,子串行可以斷續,通常用dp解決,子串要求連續。
字尾陣列可以處理一類公共子串問題,以下方法分析摘自:最長公共子串問題的字尾陣列解法 - byvoid
回顧一下字尾陣列,sa[i]表示排名第i的字尾的位置,height[i]表示字尾sa[i]和sa[i-1]的最長公共字首(longest common prefix,lcp),簡記為height[i]=lcp(sa[i],sa[i-1])。連續的一段字尾sa[i..j]的最長公共字首,就是h[i-1..j]的最小值,即lcp(sa[i..j])=min(h[i-1..j])。
求n個串的最長公共子串,可以轉化為求一些字尾的最長公共字首的最大值,這些字尾應分屬於n個串。具體方法如下:
設n個串分別為s1,s2,s3,...,sn,首先建立乙個串s,把這n個串用不同的分隔符連線起來。s=s1[p1]s2[p2]s3...sn-1[pn-1]sn,p1,p2,...pn-1應為不同的n-1個不在字符集中的字元,作為分隔符(後面會解釋為什麼)。
接下來,求出字串s的字尾陣列和height陣列,可以用倍增演算法,或dc3演算法。
然後二分列舉答案a,假設n個串可以有長度為a的公共字串,並對a的可行性進行驗證。如果驗證a可行,a'(a'於是問題就集中到了,如何驗證給定的長度a是否為可行解。方法是,找出在height陣列中找出連續的一段height[i..j],使得i<=k<=j均滿足height[k]>=a,並且i-1<=k<=j中,sa[k]分屬於原有n個串s1..sn。如果能找到這樣的一段,那麼a就是可行解,否則a不是可行解。
具體查詢i..j時,可以先從前到後列舉i的位置,如果發現height[i]>=a,則開始從i向後列舉j的位置,直到找到了height[j+1]l+n-1,所以驗證的時間複雜度為o(nl)。
到這裡,我們就可以理解為什麼分隔符p1..pn-1必須是不同的n-1個不在字符集中的字元了,因為這樣才能保證s的字尾的公共字首不會跨出乙個原有串的範圍。(否則下乙個字串的部分字首也會成為公共的部分)
poj 2774 long long message+hdu 1403 longest common substring (字尾陣列 最長公共子串) - whyorwhnt的專欄
ural 1517 freedom of choice (字尾陣列 輸出兩個串最長公共子串) - whyorwhnt的專欄
poj 3729 facer』s string (字尾陣列 兩串字尾的lcp為k的對數) - whyorwhnt的專欄
poj 1226 substrings (字尾陣列 n個串的最長公共子串) - whyorwhnt的專欄
poj 3294 life forms (字尾陣列 在n個串**現k次的最長公共子串並輸出) - whyorwhnt的專欄
poj 3080 blue jeans + hdu 2328 corporate identity (字尾陣列 字典序最小的最長公共子串) - whyorwhnt的專欄
spoj 220 relevant phrases of annihilation (字尾陣列 每個串中都至少出現兩次的不重疊最長子串) - whyorwhnt的專欄
字尾陣列 用字尾處理字串
字尾陣列處理的是文字串。我們將文字串的每一條字尾拿出來,按照字典序排序,然後就可以處理字尾陣列了。字尾陣列sa i 表示的就是排名第i位的字尾的第乙個字元所在下標。這可能有點繞口,所以我們用樣例解釋一下,如對於文字串ababa,則字尾為ababa,baba,aba,ba,a,我們排序後就是 a,ab...
字串 字尾陣列
n 字串的長度。m 當前字尾 離散化後 的值域。對於char可以跳過離散化,初值取128即可,對於int要離散化,初值取n即可,初值要保證覆蓋整個值域。sa i 排名為 i 的字尾的起始位置。rk i 起始位置為 i 的字尾的排名。驗證 const int maxn 1000000 10 int n...
最長公共字串字尾
給出若干個字串,輸出這些字串的最長公共字尾。輸入格式 由若干組輸入組成。每組輸入的第一行是乙個整數n。n為0時表示輸入結束,否則後面會繼續有n行輸入,每行是乙個字串 字串內不含空白符 每個字串的長度不超過200。輸出格式 共一行,為n個字串的最長公共字尾 可能為空 資料範圍 1 n 200輸入樣例 ...