版权声明:转载请注明原出处啦QAQ(虽然应该也没人转载): https://blog.csdn.net/hzk_cpp/article/details/86417676
题目: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;
}