BZOJ 1031 JSOI2007 字符加密Cipher 后缀数组

题目大意:给定一个字符串,求将这个字符串首尾相接后以每个字符开头的字符串排序后最后一列的字符串

传说中的后缀数组0.0 昨晚看了一晚上DC3没看懂,于是写了倍增0.0 罗先生的25行代码实在是抽象QAQ 蒟蒻表示理解不能QAQ 于是自己写了个比较清晰的版本QAQ

首先这题是环 于是我们把字符串的前n-1个字符添加到这个字符串的尾端 然后就是后缀数组的事情了

求完这个之后按照后缀数组的顺序枚举每个开头看看是不是长度大于等于n就行了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 200200
using namespace std;
int n,rank[M],sa[M];
char s[M];
int X[M],Y[M];
void Get_Rank()
{
	int i,j,tot=0;
	static pair<char,int>t[M];
	for(i=1;i<=n;i++)
		t[i]=make_pair(s[i],i);
	sort(t+1,t+n+1);
	for(i=1;i<=n;i++)
	{
		if(i==1||t[i].first!=t[i-1].first)
			++tot;
		rank[t[i].second]=tot;
	}
}
void Radix_Sort(int key[],int order[])
{
	int i;
	static int sum[M],cnt[M],temp[M];

	memset(sum,0,sizeof sum);
	memset(cnt,0,sizeof cnt);
	for(i=1;i<=n;i++)
		sum[ key[i] ]++;
	for(i=1;i<=n;i++)
		sum[i]+=sum[i-1];
	for(i=1;i<=n;i++)
		temp[ sum[key[order[i] ]-1]+ ++cnt[ key[order[i] ] ] ]=order[i];
	memcpy(order,temp,sizeof temp);
}
void Prefix_Doubling()
{
	int i,j,tot;
	Get_Rank();
	for(j=1;j<=n;j<<=1)
	{
		for(i=1;i<=n;i++)
		{
			X[i]=rank[i];
			Y[i]=i+j>n?0:rank[i+j];
			sa[i]=i;
		}
		Radix_Sort(Y,sa);
		Radix_Sort(X,sa);
		for(i=1,tot=0;i<=n;i++)
		{
			if( i==1 || X[sa[i]]!=X[sa[i-1]] || Y[sa[i]]!=Y[sa[i-1]] )
				++tot;
			rank[sa[i]]=tot;
		}
	}
}
int main()
{
	int i;
	scanf("%s",s+1);
	n=strlen(s+1);
	memcpy(s+n+1,s+1,n-1);
	n=n+n-1;
	Prefix_Doubling();
	for(i=1;i<=n;i++)
		if(sa[i]+(n>>1)<=n)
			putchar(s[sa[i]+(n>>1)]);
	cout<<endl;
	return 0;
}


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。