P3809-[模板]后缀排序(SA)

正题

题目链接:https://www.luogu.com.cn/problem/P3809


题目大意

长度为 n n 的字符串,求它的字符数组(后缀排序后排名为 i i 的在哪个位置)。


解题思路

大概思路就是倍增排序,先排每个后缀的第一个字符,然后是两个,然后是四个,以此类推。

为什么可以这样?我们由 k k 的排列拓展到 k 2 k*2 时我们将其分为双关键字排序,第 i i 位的第一关键字是第 i i 位的 k k 名次,第二关键字是第 i + k i+k 位的 k k 名次。就是说我们可以 O ( 1 ) O(1) 得出第二关键字。

然后基数排序时间复杂度 O ( n log n ) O(n\log n)


c o d e code (带注释版)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int n,m,sa[N],x[N],y[N],c[N];
char s[N];
void Qsort(){//基数排序
	for(int i=1;i<=m;i++)c[i]=0;
	for(int i=1;i<=n;i++)c[x[i]]++;
	for(int i=1;i<=m;i++)c[i]+=c[i-1];
	for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
}
void Get_SA(char *s)
{
	for(int i=1;i<=n;i++)//将第一位获取位第一关键字
		x[i]=s[i]-'0'+1,y[i]=i;
	Qsort();
	for(int w=1;w<=n;w<<=1){
		int p=0;
		for(int i=n-w+1;i<=n;i++)y[++p]=i;//将2*w位后已经没有的先丢到前面
		for(int i=1;i<=n;i++)//每个对应到其i-w的第二关键字
			if(sa[i]>w) y[++p]=sa[i]-w;
		Qsort();swap(x,y);//排序
		x[sa[1]]=p=1;
		for(int i=2;i<=n;i++)//确定新的排名并判断排序是否结束
			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+w]==y[sa[i-1]+w])?p:++p;
		if(p==n) break;m=p;
	}
	return;
}
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);m=100;
	Get_SA(s);
	for(int i=1;i<=n;i++)
		printf("%d ",sa[i]);
	return 0;
}

c o d e code (无注释版)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int n,m,sa[N],x[N],y[N],c[N];
char s[N];
void Qsort(){
	for(int i=1;i<=m;i++)c[i]=0;
	for(int i=1;i<=n;i++)c[x[i]]++;
	for(int i=1;i<=m;i++)c[i]+=c[i-1];
	for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
}
void Get_SA(char *s)
{
	for(int i=1;i<=n;i++)
		x[i]=s[i]-'0'+1,y[i]=i;
	Qsort();
	for(int w=1;w<=n;w<<=1){
		int p=0;
		for(int i=n-w+1;i<=n;i++)y[++p]=i;
		for(int i=1;i<=n;i++)
			if(sa[i]>w) y[++p]=sa[i]-w;
		Qsort();swap(x,y);
		x[sa[1]]=p=1;
		for(int i=2;i<=n;i++)
			x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+w]==y[sa[i-1]+w])?p:++p;
		if(p==n) break;m=p;
	}
	return;
}
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);m=100;
	Get_SA(s);
	for(int i=1;i<=n;i++)
		printf("%d ",sa[i]);
	return 0;
}
发布了867 篇原创文章 · 获赞 55 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/104076715