洛谷P3809 【模板】后缀排序(后缀数组模板)

题目背景

这是一道模板题。

题目描述

读入一个长度为 nn 的由大小写英文字母或数字组成的字符串,请把这个字符串的所有非空后缀按字典序从小到大排序,然后按顺序输出后缀的第一个字符在原串中的位置。位置编号为 11 到 nn 。

输入输出格式

输入格式:

一行一个长度为 nn 的仅包含大小写英文字母或数字的字符串。

输出格式:

一行,共n个整数,表示答案。

输入输出样例

输入样例#1: 复制

ababa

输出样例#1: 复制

5 3 1 4 2

说明

n <= 10^6n<=106

题解:

后缀数组模板题。

后缀数组的思想很简单,但具体方面实在是有些难以理解,但也不至于有后缀自动机那么难,我看了一个晚上才看明白。

写的很好

不复习估计很快就忘了,要经常复习才行(我现在就有点迷了)。

代码:

#include<bits/stdc++.h>
using namespace std;
int M,n,m,tax[1000001],rak[1000001],sa[1000001],tp[1000001];
char s[1000001];
void px(){
	int i;
	for(i=0;i<=M;i++)tax[i]=0;
	for(i=1;i<=n;i++)tax[rak[i]]++;
	for(i=1;i<=M;i++)tax[i]+=tax[i-1];
	for(i=n;i;i--)sa[tax[rak[tp[i]]]--]=tp[i];
}
void getsuffix(){
	int i,m,p;
	M=100;
	for(i=1;i<=n;i++)rak[i]=s[i]-'0',tp[i]=i;
	px();
	for(m=1,p=0;p<n;M=p,m*=2){
		p=0;
		for(i=1;i<=m;i++)tp[++p]=n-m+i;
		for(i=1;i<=n;i++)
		 if(sa[i]>m)tp[++p]=sa[i]-m;
		px();
		swap(tp,rak);
		rak[sa[1]]=p=1;
		for(i=2;i<=n;i++)
		 rak[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+m]==tp[sa[i]+m])?p:++p; 
	}
}
int main(){
	int i;
	scanf("%s",s+1);
	n=strlen(s+1);
	getsuffix();
	for(i=1;i<=n;i++)printf("%d ",sa[i]);
}

猜你喜欢

转载自blog.csdn.net/qq_41510496/article/details/81194349