题意:
N个数字组成的序列A1,A2,A3...An。其中,A1最大,现在要把整个序列分成三段,并将三段反转,求能得到的字典序最小的序列是什么?要求分得的每段都不为空。
第一段分割比较简单,反转利用后缀数组即可;剩余的二三段不是独立的,不能光比较前半部分的字典序取其中最小者,我们可以反转二三段并重复2次,再计算其后缀数组,且sa[0]的开始位置应在序列的前半部分,这样,二三段就是按整体考虑了。
代码:(后缀数组)
//输入
int N,A[max_n];
int rev[max_n*2],sa[max_n*2];
void solve()
{
//将A反转,并计算其后缀数组
reverse_copy(A,A+N,rev);
creat_sa(rev,N,sa);
//确定第一段的分割位置
int p1;
for(int i=0;i<N;i++)
{
p1=N-sa[i];
if(p1>=1&&N-p1>=2)
break;
}
//将p1之后的字符串反转并重复2次,再计算其后缀数组
int m=N-p1;
reverse_copy(A+p1,A+N,rev);
reverse_copy(A+p1,A+N,rev+m);
creat_sa(rev,m*2,sa);
//确定后两段的划分位置
int p2;
for(int i=0;i<=2*m;i++)
{
p2=p1+m-sa[i];
if(p2-p1>=1&&N-p2>=1) break;
}
reverse(A,A+p1);
reverse(A+p1,A+p2);
reverse(A+p2,A+N);
for(int i=0;i<N;i++)
printf("%d\n",A[i]);
}