• POJ 3581 Sequence [后缀数组]


    Sequence
    Time Limit: 5000MS   Memory Limit: 65536K
    Total Submissions: 6911   Accepted: 1543
    Case Time Limit: 2000MS

    Description

    Given a sequence, {A1A2, ..., An} which is guaranteed AA2, ..., 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 {A1A2, ..., An} and {B1B2, ..., Bn}, we say {A1A2, ..., An} is smaller than {B1B2, ..., Bn} if and only if there exists such i ( 1 ≤ i ≤ n) 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}

    Source


    题意:

    给出一个字符串,要求将其切成3段,然后将每段翻转,使得得到的新串字典序最小
    保证原串第一个字符的字典序比后面的都大


    字符串反转后求最小后缀就是第一段啦
    后两段的话,保持反转不变,然后复制一份接在后面求最小后缀就行了,自己画图看看吧
    注意判断位置的合法性,比如需要分成三份,以及第二次不能分在复制的那一份上
     
    还有,需要离散化........
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=2e5+5,INF=1e9;
    inline int read(){
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1; c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0'; c=getchar();}
        return x*f;
    }
    int n,m,c[N],t1[N],t2[N];
    int s[N],mp[N];
    void iniMP(){
        sort(mp+1,mp+1+n);
        int p=0;mp[++p]=mp[1];
        for(int i=2;i<=n;i++) if(mp[i]!=mp[i-1]) mp[++p]=mp[i];
        mp[0]=p;
    }
    int Bin(int v){
        int l=1,r=mp[0];
        while(l<=r){
            int mid=(l+r)>>1;
            if(v==mp[mid]) return mid;
            else if(v<mp[mid]) r=mid-1;
            else l=mid+1;
        }
        return 0;
    }
    
    int sa[N],rnk[N],height[N];
    inline bool cmp(int *r,int a,int b,int j){
        return a+j<=n&&b+j<=n&&r[a]==r[b]&&r[a+j]==r[b+j];
    }
    void getSA(int s[]){
        m=mp[0];
        int *r=t1,*k=t2;
        for(int i=0;i<=m;i++) c[i]=0;
        for(int i=1;i<=n;i++) c[r[i]=s[i]]++;
        for(int i=1;i<=m;i++) c[i]+=c[i-1];
        for(int i=n;i>=1;i--) sa[c[r[i]]--]=i;
    
        for(int j=1;j<=n;j<<=1){
            int p=0;
            for(int i=n-j+1;i<=n;i++) k[++p]=i;
            for(int i=1;i<=n;i++) if(sa[i]>j) k[++p]=sa[i]-j;
    
            for(int i=0;i<=m;i++) c[i]=0;
            for(int i=1;i<=n;i++) c[r[k[i]]]++;
            for(int i=1;i<=m;i++) c[i]+=c[i-1];
            for(int i=n;i>=1;i--) sa[c[r[k[i]]]--]=k[i];
    
            swap(r,k);p=0;r[sa[1]]=++p;
            for(int i=2;i<=n;i++) r[sa[i]]=cmp(k,sa[i],sa[i-1],j)?p:++p;
            if(p>=n) break;m=p;
        }
    }
    
    void solve(){
        reverse(s+1,s+1+n);
        getSA(s);
        int p=1;
        while(sa[p]<=2) p++;
        for(int i=sa[p];i<=n;i++) printf("%d
    ",mp[s[i]]);
    
        n=sa[p]-1;
        for(int i=1;i<=n;i++) s[i+n]=s[i];
        n<<=1;
        getSA(s);
        p=1;
        n>>=1;
        while(sa[p]==1||sa[p]>n) p++;
        for(int i=sa[p];i<=n;i++) printf("%d
    ",mp[s[i]]);
        for(int i=1;i<sa[p];i++) printf("%d
    ",mp[s[i]]);
    }
    
    int main(){
        freopen("in","r",stdin);
        n=read();
        for(int i=1;i<=n;i++) s[i]=mp[i]=read();
        iniMP();
        for(int i=1;i<=n;i++) s[i]=Bin(s[i]);
        solve();
    }
     
     
     
     
  • 相关阅读:
    oracle 11g完全彻底的卸载
    Windows添加.NET Framework 3.0 NetFx3 失败
    Crontab中的除号(slash)到底怎么用?
    Codeigniter文件上传类型不匹配错误
    Mac下遇到 'reading initial communication packet’ 问题
    使用PHP的正则抓取页面中的网址
    关于Advertising Campaign
    20个Linux服务器安全强化建议(三)
    20个Linux服务器安全强化建议(二)
    20个Linux服务器安全强化建议(一)
  • 原文地址:https://www.cnblogs.com/candy99/p/6370228.html
Copyright © 2020-2023  润新知