P4051 [JSOI2007]字符加密(SA)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4051 [JSOI2007]字符加密(SA)相关的知识,希望对你有一定的参考价值。

P4051 [JSOI2007]字符加密(SA)

就是SA排序后,按排名输出 ( s a [ i ] ≤ n ) (sa[i]\\le n) (sa[i]n) 的所有 s t r [ s a [ i ] + n − 1 ] str[sa[i]+n-1] str[sa[i]+n1]的位置。

这里多出来的后缀长度不会影响相对排名,因为多出来的后缀相当于原串的前缀。

// Problem: P4051 [JSOI2007]字符加密
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4051
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-10-16 16:58:59
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=2e5+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define x first
#define y second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define ios ios::sync_with_stdio(false),cin.tie(nullptr) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
char s[N];//字符串 
int sa[N],rk[N],tp[N],b[N],n,sz;
//sa[i]  排名为i的后缀的下标	即后缀数组 
//rk[i]  下标为i的后缀的排名
//tp[i]  按第二关键字排名为i的下标
//b[i] 排名为i的桶
// n 字符串大小
// sz 字符集大小 
void Qsort(){		//基数排序 
	for(int i=1;i<=sz;i++) b[i]=0;	//清空桶
	for(int i=1;i<=n;i++) b[rk[i]]++; //排名放入桶里 
	for(int i=1;i<=sz;i++) b[i]+=b[i-1]; //计算排名.
	for(int i=n;i>=1;i--) sa[b[rk[tp[i]]]--]=tp[i];
	//当第一关键字排名相同时,按照第二关键字排名从小到大进行 更新sa[]  
	//这里倒序是求的  当第一关键字排名相同时,第二关键字排名靠后的后缀的下标. 
}
void SA(){
	sz=500;//只计算字母,数字的话 80足以了. 
	for(int i=1;i<=n;i++) rk[i]=(int)s[i],tp[i]=i;//初始化rk和tp.  
	Qsort();//求开始的sa[] 
	for(int w=1,id=0;id<n;w<<=1,sz=id){	//w表示已经得到的倍增长度 id表示当前排名的个数. O(logn)
		id=0;
		for(int i=n-w+1;i<=n;i++) tp[++id]=i;//[n-w+1,n]开始的后缀的后w个字符(没有字符)都是最小的. 
		for(int i=1;i<=n;i++) if(sa[i]>w) tp[++id]=sa[i]-w;//用后w的sa 来更新tp
		Qsort();	//求出2w的sa	O(n)
		swap(rk,tp);	//此时的tp已经没用了,tp初始化为这一轮的rk,用来更新下一轮的rk 
		rk[sa[1]]=id=1;	//更新下一轮的rk 
		for(int i=2;i<=n;i++)	//用sa[] 和tp[](即上一轮的rk[]) 更新下一轮rk[] 
			rk[sa[i]] = (tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+w]==tp[sa[i-1]+w])?id:++id;
	} 		//如果第一关键字排名和第二关键字排名相同 即rk相同为id, 否则++id; 
} 
int main(){
	scanf("%s",s+1);n=strlen(s+1);
	for(int i=1;i<=n;i++) s[n+i]=s[i];
	s[2*n+1]='\\0';
	int nn=n;
	n<<=1;
	SA();
	for(int i=1;i<=n;i++)
		if(sa[i]<=nn)
			{
				printf("%c",s[sa[i]+nn-1]);
			}
	return 0;
}

以上是关于P4051 [JSOI2007]字符加密(SA)的主要内容,如果未能解决你的问题,请参考以下文章

P4051 [JSOI2007]字符加密

P4051 [JSOI2007]字符加密 解题报告

P4051 [JSOI2007]字符加密

P4051 [JSOI2007]字符加密

洛谷P4051 [JSOI2007]字符加密

[JSOI2007]字符加密