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

      

  • 相关阅读:
    ZOJ 3818 Pretty Poem
    HDU 4597 Play Game
    HDU 4497 GCD and LCM
    CSU 1335 高桥和低桥
    UVA 10791 Minimum Sum LCM
    CSU 1119 Collecting Coins
    CSU 1120 病毒
    UVA 12169 Disgruntled Judge
    HDU 1301 Jungle Roads
    POJ 1258 Agri-Net
  • 原文地址:https://www.cnblogs.com/forever97/p/poj3581.html
Copyright © 2011-2022 走看看