題目大意:給出一個包含大寫字母的長度爲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;
}