寫了好久才把字尾陣列的專題寫完= =。。。
字尾陣列就是對字串的所有字尾來搞事,通過對這些字尾排序,來得到這些字尾之前存在的關係。
字尾陣列中的sa陣列(排名陣列)和height(相鄰排名lcp)有很多很有用的特性,使得在處理一些字串問題的時候很給力,比較流行的求字尾陣列的演算法有o(nlogn)的倍增求法和o(n)的dc3(並不會)。
height陣列滿足特性:sa[i]與saj的最長公共字首是height[i+1]到height[j]這段區間的最小值。所以問題就可以轉化成求區間最小值,同樣也可以用倍增法解決這個問題,達到o(nlogn)初始化和o(1)查詢。
跟sa相關的題目很多都涉及了多字串,常用策略就是將字串全都拼接在一起,中間使用不同的不會出現的字元分隔開他們;還有height陣列分組也是比較常見的做法,將連續一段滿足height全都大於等於k的分成一組,這組裡的所有字尾相互就都滿足最長公共字首大於等於k,如果這裡面的字尾來自n個不同的字串,那就說明了這n個字串內存在了長度為k的公共子串。
同時,sa陣列是字尾的字典序排序,所以有些題目需要字典序最小答案也可以通過sa陣列輕易的獲得。
二分答案判斷是否滿足也是比較常見的解題方法。
kuangbin大神的字尾陣列專題裡的題目幾乎都是來自那篇著名的字尾陣列的**,所以都可以在裡面找到解題思路。
求陣列裡不重疊的變化相同的最長公共子串。
將陣列處理一下,a[i]變成a[i]-a[i-1],陣列就符合題目要求了,二分答案k,然後就可以用上述的height陣列分塊的方法將每乙個height陣列都大於等於k的區間分為一塊,要求不重疊,就是要使得分塊中sa最大值和最小值對應的字尾下標差大於等於k。
求字串中出現了k次的可重疊子串,大體做法和上面那題差不多,二分答案後判斷的方式略有不同,存在乙個height陣列的分塊大於等於k就滿足條件。#include
#include
using
namespace
std;
const
int maxn=20005;
const
int maxm=1005;
int n;
int r[maxn];
int sa[maxn],t1[maxn],t2[maxn],c[maxn];
int rank[maxn],height[maxn];
bool cmp(int *r,int a,int b,int l)
void get_sa(int str,int sa,int rank,int height,int n,int m)
int k = 0;
n--;
for(i = 0;i <= n;i++)rank[sa[i]] = i;
for(i = 0;i < n;i++)
}bool func(int k)
if(maxx-minn>=k)return
1; maxx=minn=sa[i];
}return0;}
int main()
else rig=mid-1;
}ans++;
if(ans<5)printf("0\n");
else
printf("%d\n",ans);
}}
尋找字串中不相同子串的數量,也是可以利用height陣列完成的事情,height[i]表示sa[i]和sa[i-1]的公共字首,n-sa[i-1]-height[i]就是sa[i-1]對應的字尾可以產生的與sa[i]不同的子串,正著掃一邊就可以處理出答案來了。#include
#include
using
namespace
std;
typedef
long
long ll;
const
int maxn=20015;
const
int maxm=10005;
const ll mod=1e9+7;
int n,m,k;
struct nodenum[maxn];
bool cmp1(node a,node b)
void build_sa(int n,int m)
bool judge(int len)
else
if(cnt>=k)
}return0;}
int main()
r[num[i].id]=cur;
}r[n]=0;
build_sa(n,n+1);
int lef=0,rig=n,ans=0;
while(lef<=rig)
else rig=mid-1;
}printf("%d\n",ans);
return
0;}
#include
#include
#include
using
namespace
std;
const
int maxn=1005;
const
int maxm=400005;
int n,cas;
char str[maxn];
int r[maxn];
int ans[maxn];
int sa[maxn],t1[maxn],t2[maxn],c[maxn];
int rank[maxn],height[maxn];
bool cmp(int *r,int a,int b,int l)
void get_sa(int n,int m)
int k = 0;
n--;
for(i = 0;i <= n;i++)rank[sa[i]] = i;
for(i = 0;i < n;i++)
}struct nodein[maxn];
bool cmp1(node a,node b)
printf("%d\n",ans);
}return
0;}
kuangbin帶你飛專題
kuangbin帶你飛 專題一 簡單搜尋 kuangbin帶你飛 專題二 搜尋高階 kuangbin帶你飛 專題三 dancing links kuangbin帶你飛 專題四 最短路練習 kuangbin帶你飛 專題五 並查集 kuangbin帶你飛 專題六 最小生成樹 kuangbin帶你飛 專題...
kuangbin帶你飛 專題一 簡單搜尋 D
n m的0 1格仔,目標是全變成0 每次反轉乙個,身邊的4個都變成相反的 0變1,1變0 問最少反轉多少個,每個格仔如果翻了填1,沒翻填0 乍一看挺恐怖的,首先想到乙個格仔不可能翻轉兩次,因為反轉兩次就變回了原來的樣子,就是相當於浪費,那麼每個格仔就是翻轉或者不翻轉兩種可能,而當第一行確定下來翻轉與...
kuangbin帶你飛專題1(搜尋)A 棋盤問題
先上題 在乙個給定形狀的棋盤 形狀可能是不規則的 上面擺放棋子,棋子沒有區別。要求擺放時任意的兩個棋子不能放在棋盤中的同一行或者同一列,請程式設計求解對於給定形狀和大小的棋盤,擺放k個棋子的所有可行的擺放方案c。input 輸入含有多組測試資料。每組資料的第一行是兩個正整數,n k,用乙個空格隔開,...