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]+n−1]的位置。
这里多出来的后缀长度不会影响相对排名,因为多出来的后缀相当于原串的前缀。
// 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)的主要内容,如果未能解决你的问题,请参考以下文章