题目大意:给你一个字符串,每次可以从头或尾取一个字符加入新字符串,要求最小化新字符串的字典序
题解:考虑贪心,若左右不同选较小的,若相同就找到第一个不同的位置比较
中间加一个分隔符,把反串接在后面,用rank数组就可以比较了
我的收获:SA!
#include <bits/stdc++.h>
using namespace std;
const int N=100005;
int n,len;
int sa[N],rk[N],rk2[N],c[N];
char s[N];
int cmp(int *r,int a,int b,int l){return (r[a]==r[b])&&(r[a+l]==r[b+l]);}
void DA(int n,int m=128){
int i,k,p,*x=rk,*y=rk2;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[i]=s[i]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for(k=1,p=1;p<n;k<<=1,m=p){
for(p=0,i=n-k;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k;
for(i=0;i<m;i++) c[i]=0;
for(i=0;i<n;i++) c[x[y[i]]]++;
for(i=1;i<m;i++) c[i]+=c[i-1];
for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y),p=1,x[sa[0]]=0;
for(i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?p-1:p++;
}
}
void work()
{
for(int i=1;i<=n;i++) rk[sa[i]]=i;
int l=0,r=len+1;
for(int i=0;i<len;i++){
if(rk[l]<rk[r]) putchar(s[l++]);
else putchar(s[r++]);
if(!((i+1)%80)) putchar('\n');
}
}
void init()
{
scanf("%d",&n);s[n]='$';len=n;
for(int i=0;i<n;i++){
char ch;
scanf("%*c%c",&ch);
s[2*n-i]=s[i]=ch;
}
n=n+n+1;s[n]=0;DA(n+1);
}
int main()
{
init();
work();
return 0;
}