藍書(演算法競賽進階指南)刷題記錄——CH1402 字尾陣列(二分+hash+快排)
阿新 • • 發佈:2019-01-13
題目:CH1401.
題目大意:求出一個字串的所有後綴的排名,以及排名為i與i-1的字尾的最長公共字首LCP.
這道題一看是字尾陣列裸題,但是我不會 為了學習hash,我們考慮hash的寫法.
考慮SA的求法,顯然直接排序的串長是 的,所以總複雜度會達到 直接TLE.那麼考慮用Hash優化串的比較過程,想到兩個串的大小比較由第一個不相等的字元決定,也就是由兩個串最長公共字首LCP的後一個字元決定,所以二分LCP長度即可.時間複雜度 .
再來考慮Height陣列的求法,發現Height陣列的本質就是求n-1次LCP,所以我們也可以使用二分求LCP做到 解決這個問題.
程式碼如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
typedef unsigned long long ULL;
const int N=300000;
const ULL P=131;
char c[N+9];
int n,sa[N+9],hei[N+9];
ULL s[N+9],Pow[N+9];
ULL Hash(ULL *s,int l,int r){return s[r]-s[l-1]*Pow[r-l+1];}
int LCP(int a,int b){
int l=0,r=min(n-a+1,n-b+1);
for (int mid=l+r>>1;l+1<r;mid=l+r>>1)
Hash(s,a,a+mid-1)==Hash(s,b,b+mid-1)?l=mid:r=mid;
return Hash(s,a,a+r-1)==Hash(s,b,b+r-1)?r:l;
}
bool cmp(const int &a,const int &b){
int lcp=LCP(a,b);
return c[a+lcp]<c[b+lcp];
}
Abigail into(){
scanf("%s",c+1);
n=strlen(c+1);
}
Abigail work(){
Pow[0]=1;
for (int i=1;i<=n;++i){
sa[i]=i;
s[i]=s[i-1]*P+c[i];
Pow[i]=Pow[i-1]*P;
}
sort(sa+1,sa+1+n,cmp);
for (int i=2;i<=n;++i)
hei[i]=LCP(sa[i],sa[i-1]);
}
Abigail outo(){
for (int i=1;i<n;++i)
printf("%d ",sa[i]-1);
printf("%d\n",sa[n]-1);
for (int i=1;i<n;++i)
printf("%d ",hei[i]);
printf("%d\n",hei[n]);
}
int main(){
into();
work();
outo();
return 0;
}