POJ 3581 Sequence(后缀数组)

题意:

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]);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值