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

                                                                                                                           Sequence

    Given a sequence, {A1, A2, ..., An} which is guaranteed A1 > A2, ..., An,  you are to cut it into three sub-sequences and reverse them separately to form a new one which is the smallest possible sequence in alphabet order.

    The alphabet order is defined as follows: for two sequence {A1, A2, ..., An} and {B1, B2, ..., Bn}, we say {A1, A2, ..., An} is smaller than {B1, B2, ..., Bn} if and only if there exists such i ( 1 ≤ in) so that we have Ai < Bi and Aj = Bj for each j < i.

    Input

    The first line contains n. (n ≤ 200000)

    The following n lines contain the sequence.

    Output

    output n lines which is the smallest possible sequence obtained.

    Sample Input

    5
    10
    1
    2
    3
    4
    

    Sample Output

    1
    10
    2
    4
    3
    

    Hint

    {10, 1, 2, 3, 4} -> {10, 1 | 2 | 3, 4} -> {1, 10, 2, 4, 3}
     
    题意:给定N个数字组成的序列 A1 A2....AN.其中A1比其他数字都大。 现在要把这个序列分成三段,并将每段分别反转,求能得到的字典序最小的序列是什么?  要求分得的每段都不为空
     
    分析: 可以先将字符串反转,这样的话,因为A1比其他数字都大,找到后缀最小的位置,一定分隔出第一段.(如果没有这个条件的话,1123中第一段应分隔为11,但找最小后缀为1)
               对于剩下的部分不能直接找后缀最小的位置  比如  剩下两段为3 1 2 3 1 4,最后应得到132134,如果直接找后缀最小的位置就会变成134132,因为它反转后,最小的后缀是1 3,但我们应找的是 1 3 2 1 3,所以这个时候要保证剩下的两段最小的话,3 1 2 3 1 4反转为 4 1 3 2 1 3  ,反转后的部分会与剩下的部分相连接,所以我们在找后缀的时候将长度*2就能保证整体的字典序最小
              还有个问题就是这个题中,序列中ai的取值范围为int   
               在后缀数组中,最大的数应小于MAXN
               所以我们还需要进行离散化
               这里离散化的时候,我直接用的map,用时较高,但也没超时
    代码如下:
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <map>
    typedef long long ll;
    using namespace std;
    const int MAXN=400010;
    int wa[MAXN],wb[MAXN],wv[MAXN],Ws[MAXN];
    char str[MAXN];
    int r2[MAXN];
    int vis[MAXN];  //用来记录离散化之前数的大小
    map<int,int>mp;
    int cnt;
    int insert1(int x)  //离散化操作
    {
     if(mp.find(x)==mp.end())mp[x]=cnt++;
      return mp[x];
    }
    struct node
    {
        int num;
        int id;
    }r[MAXN];
    int cmp2(node x,node y)
    {
        return x.num<y.num;
    }
    int cmp(int *r,int a,int b,int l)
    {return r[a]==r[b]&&r[a+l]==r[b+l];}
    void da(int r[],int sa[],int n,int m)  //n为len+1,m一般比数组中最大的数大一点即可
    {
          int i,j,p,*x=wa,*y=wb,*t;
          for(i=0; i<m; i++) Ws[i]=0;
          for(i=0; i<n; i++) Ws[x[i]=r[i]]++;
          for(i=1; i<m; i++) Ws[i]+=Ws[i-1];
          for(i=n-1; i>=0; i--) sa[--Ws[x[i]]]=i;
          for(j=1,p=1; p<n; j*=2,m=p)
          {
                for(p=0,i=n-j; i<n; i++) y[p++]=i;
                for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
                for(i=0; i<n; i++) wv[i]=x[y[i]];
                for(i=0; i<m; i++) Ws[i]=0;
                for(i=0; i<n; i++) Ws[wv[i]]++;
                for(i=1; i<m; i++) Ws[i]+=Ws[i-1];
                for(i=n-1; i>=0; i--) sa[--Ws[wv[i]]]=y[i];
                for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
                      x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
          }
          return;
    }
    int sa[MAXN],Rank[MAXN],height[MAXN];// sa是通过后缀排名找到它在字符串中的位置,rank是根据位置找到后缀排名,两者相逆,该模板中sa数组的最小值为1。
    
    void calheight(int *r,int *sa,int n)
    {
          int i,j,k=0;
          for(i=1; i<=n; i++) Rank[sa[i]]=i;
          for(i=0; i<n; height[Rank[i++]]=k)
                for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++);
    }
    int main()
    {
      int n,maxx,tag,tag2,tag3,maxrank,len;
         scanf("%d",&n);
         cnt=1;
          maxx=0;
          for(int i=0;i<n;i++){
          scanf("%d",&r[i].num);
          r[i].id=i;
          }
          sort(r,r+n,cmp2);//从小到大的排序 为了进行离散化
         for(int i=0;i<n;i++){
            //r2[n-1-r[i].id]=r[i].num;
            r2[n-1-r[i].id]=insert1(r[i].num);//离散化
            vis[r2[n-1-r[i].id]]=r[i].num;
            maxx=max(maxx, r2[n-1-r[i].id]);
          }
          r2[n]=0;
         da(r2,sa,n+1,maxx+10);
         calheight(r2,sa,n);
           maxrank=MAXN+10;
         for(int i=2;i<n;i++)
         {
            if(Rank[i]<maxrank)
            {
              tag=i;            //分隔出第一段
              maxrank=Rank[i];
            }
         }
        // cout<<"  "<<tag<<endl;
          for(int i=tag;i<=n-1;i++)
            printf("%d
    ",vis[r2[i]]);
          len=tag;
          for(int i=0;i<len;i++)
             r2[len+i]=r2[i];  //剩下的部分进行复制
          len=2*len;
          r2[len]=0;
          da(r2,sa,len+1,maxx+10);
          calheight(r2,sa,len);
           maxrank=MAXN+10;
        for(int i=1;i<len/2;i++)
        {
           if(Rank[i]<maxrank)
           {
               maxrank=Rank[i];
               tag2=i;
           }
    
        }
         for(int i=tag2;i<tag2+len/2;i++)
         {
             printf("%d
    ",vis[r2[i]]);
         }
    return 0;
    }
         
                
  • 相关阅读:
    笔记本搜不到无线网络连接[转]
    局域网IP冲突
    CFree 修改/添加编译配置环境(Build Configuration)
    字母索引网页
    NAOChoregraphe"单机使用许可证使用了多次"问题解决方案
    redis源码笔记-dict.c
    redis源码笔记-sds
    redis源码笔记-testhelp
    redis源码笔记-endian
    redis源码笔记-dict.h
  • 原文地址:https://www.cnblogs.com/a249189046/p/7476245.html
Copyright © 2011-2022 走看看