题目大意:给出一个包含大写字母的长度为n的字符串,每次可以从字符串的首或尾取出一个字符放在新串的末尾,输出字典序最小的新串
当首尾相同时,找第一个不同的位置谁小取谁,然而复杂度是O(n)的。
可以将正反串中间用符号隔开连在一起,求出后缀数组,这样取rank较小的就可以了
#include <cstdio>
#define max(a,b) ((a)>(b)?(a):(b))
#define N 60005
using namespace std;
int n,len,sa[N],rnk[N];
char s[N];
void Radix_sort(int key[]) {
static int t[N],tmp[N];
for(int i=0;i<=len;i++) t[i]=0;
for(int i=1;i<=len;i++) t[key[i]]++;
int lim=max(len,'Z');
for(int i=1;i<=lim;i++) t[i]+=t[i-1];
for(int i=len;i;i--) tmp[t[key[sa[i]]]--]=sa[i];
for(int i=1;i<=len;i++) sa[i]=tmp[i];
return ;
}
void get_SA() {
static int x[N],y[N];
for(int i=1;i<=len;i++) x[i]=s[i], sa[i]=i;
Radix_sort(x);
int tot=0;
for(int j=1;j<=len;j++) {
if(j==1 || x[sa[j]]!=x[sa[j-1]] || y[sa[j]]!=y[sa[j-1]]) tot++;
rnk[sa[j]]=tot;
}
for(int i=1;i<=len;i*=2) {
for(int j=1;j<=len;j++)
x[j]=rnk[j], y[j]=i+j>len ? 0 : rnk[i+j], sa[j]=j;
Radix_sort(y), Radix_sort(x);
tot=0;
for(int j=1;j<=len;j++) {
if(j==1 || x[sa[j]]!=x[sa[j-1]] || y[sa[j]]!=y[sa[j-1]]) tot++;
rnk[sa[j]]=tot;
}
}
return ;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%s",s+i);
len=n*2+1;
s[n+1]='@';
for(int i=0;i<n;i++) s[len-i]=s[i+1];
get_SA();
int l=1,r=n+2;
for(int i=1;i<=n;i++) {
if(rnk[l]<rnk[r] && l<=n) printf("%c",s[l++]);
else printf("%c",s[r++]);
if(i%80==0) printf("\n");
}
return 0;
}