后缀数组
题意很简单,就是给字符串排序然后依次输出最后一个字符。
而对于字符串排序我们有后缀数组这个东西。
因为要接环,于是把s*2,然后构造后缀数组即可。
输出时过滤位置≥原字符串长度的字符(n)(即长度≤n/2)。
因为要输出最后一个,把位置加上原字符串长度即可
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define MAXN 200000
using namespace std;
int n,m,q;
int sa[MAXN+5],rk[MAXN+5],rs[MAXN+5],t[MAXN+5];
char s[MAXN+5];
void RS(){//基数排序
memset(rs,0,sizeof(rs));
for (int i=1;i<=q;i++) rs[rk[t[i]]]++;
for (int i=1;i<=m;i++) rs[i]+=rs[i-1];
for (int i=q;i>=1;i--) sa[rs[rk[t[i]]]--]=t[i];
}
void SA(){//求后缀数组
m=127; q=strlen(s+1);//题目说可能是任意的字符,于是假设当前127个字符都出现
for (int i=1;i<=q;i++){
rk[i]=s[i]; t[i]=i;
}
RS();
for (int k=1;k<=q;k*=2){
int p=0;
for (int i=n-k+1;i<=q;i++) t[++p]=i;
for (int i=1;i<=n;i++)
if (sa[i]>k) t[++p]=sa[i]-k;
RS(); memcpy(t,rk,sizeof(t));
p=1; rk[sa[1]]=1;
for (int i=2;i<=q;i++)
if (t[sa[i]]==t[sa[i-1]]&&t[sa[i]+k]==t[sa[i-1]+k]) rk[sa[i]]=p;
else rk[sa[i]]=++p;
if (p==q) break;
m=p;
}
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
for (int i=1;i<=n;i++)
s[i+n]=s[i];
n=strlen(s+1);
SA();
for (int i=1;i<=n;i++)
if (sa[i]<=n/2) printf("%c",s[sa[i]+n/2-1]);
//把位置≤n/2的输出
printf("\n");
return 0;
}