zoukankan      html  css  js  c++  java
  • POJ 3581 Sequence(后缀数组)

    【题目链接】 http://poj.org/problem?id=3581

     

    【题目大意】

      给出一个数列,将这个数列分成三段,每段分别翻转,使得其字典序最小,输出翻转后的数列。

     

    【题解】

      首先,第一个翻转点就是翻转后数列的最小后缀,注意由于一定要分成三段,则至少要剩下两个元素。难点主要是如何处理第二个翻转点,我们发现剩余的部分的每一种翻转拆分都是将两串翻转后剩余部分拼接在一起得到的串的子串,所以我们将剩余部分翻转,复制一份拼接在后面,求最小后缀即可。

    【代码】

    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    using namespace std;
    const int N=800010;
    int n,rank[N],sa[N],h[N],tmp[N],cnt[N],ans; int s[N]; 
    void suffixarray(int n,int m){
        int i,j,k;n++;
        for(i=0;i<2*n+5;i++)rank[i]=sa[i]=h[i]=tmp[i]=0;
        for(i=0;i<m;i++)cnt[i]=0;
        for(i=0;i<n;i++)cnt[rank[i]=s[i]]++;
        for(i=1;i<m;i++)cnt[i]+=cnt[i-1];
        for(i=0;i<n;i++)sa[--cnt[rank[i]]]=i;
        for(k=1;k<=n;k<<=1){
            for(i=0;i<n;i++){
                j=sa[i]-k;
                if(j<0)j+=n;
                tmp[cnt[rank[j]]++]=j;
            }sa[tmp[cnt[0]=0]]=j=0;
            for(i=1;i<n;i++){
                if(rank[tmp[i]]!=rank[tmp[i-1]]||rank[tmp[i]+k]!=rank[tmp[i-1]+k])cnt[++j]=i;
                sa[tmp[i]]=j;
            }memcpy(rank,sa,n*sizeof(int));
            memcpy(sa,tmp,n*sizeof(int));
            if(j>=n-1)break;
        }for(j=rank[h[i=k=0]=0];i<n-1;i++,k++)
        while(~k&&s[i]!=s[sa[j-1]+k])h[j]=k--,j=rank[sa[j]+1];
    }
    int disc[N];
    int remark(int x){
    	  int l=1,r=n;
    	  while(l<=r){
    		    int mid=(l+r)>>1;
    		    if(disc[mid]<x)l=mid+1;
    		    else if(disc[mid]==x)return mid;
    		    else r=mid-1;
    	  }
    }
    int a[N],p1,p2;
    int main(){
        scanf("%d",&n);
        for(int i=0;i<n;i++)scanf("%d",a+i),disc[i+1]=a[i];
        sort(disc+1,disc+n+1);
        for(int i=0;i<n;i++)a[i]=remark(a[i]);
        reverse_copy(a,a+n,s);
        suffixarray(n,n+1);
        for(int i=0;i<=n;i++){p1=n-sa[i];if(p1>=1&&n-p1>=2)break;}
        int m=n-p1;
        reverse_copy(a+p1,a+n,s);
        reverse_copy(a+p1,a+n,s+m);
        suffixarray(m<<1,n+1);
        for(int i=0;i<=2*m;i++){p2=p1+m-sa[i];if(p2>p1&&n>p2)break;}
        reverse(a,a+p1);reverse(a+p1,a+p2);reverse(a+p2,a+n);
        for(int i=0;i<n;i++)printf("%d
    ",disc[a[i]]);
        return 0;
    }
    

      

  • 相关阅读:
    关于Ubuntu 9.10 的aptget update 一直无法更新源的点点滴滴
    CentOS的安装和搭建文件共享服务器(Samba)
    VirtualBox 下的 Ubuntu 虚拟机中使用 Android 真机做开发调试
    VmWare下安装CentOS6图文安装教程
    CentOS的远程桌面(xdm)
    ubuntu Apache安装设置
    关于母版页的按钮事件
    TSQL使用函数uppercase更新xml
    文章的上一篇和下一篇导航 V2
    数据库用户映射到 SQL Server 登录名
  • 原文地址:https://www.cnblogs.com/forever97/p/poj3581.html
Copyright © 2011-2022 走看看