poj3581 Sequence (后缀数组)

Time Limit: 5000MS   Memory Limit: 65536K
Total Submissions: 6305   Accepted: 1364
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}


题意:给你n个数(保证第一个数字大于这n个数的其他任何数字),让你把这n个数分成三份,每一份必须至少含有一个数字,然后把这三份的数字倒置,再把这三部分拼成一个串,并且要使得这个字符串的字典序最小。

思路:先考虑第一段,因为第一个数字大于这n个数的其他任何数字,所以我们可以把字符串取反,然后找到字典序最小的后缀作为第一段,还要保证后缀的长度不超过n-2,如果超过后面就不能分成两个串(如果这里不懂可以画一下).然后我们把剩下的字符串取出来,表示成长度为m的a[]数组,接下来的问题就变为怎么样找到一个分割点k,使得a[0],a[1],...a[k]的反串和a[k+1],a[k+2]...a[m-1]的反串连接起来的串的字典序最小,我们转化一下就变为求分割点k,使得a[k],a[k-1]...a[0],a[m-1],a[m-2]...a[k+1]的字典序最小,我们发现,a[k],a[k-1]...a[0],a[m-1],a[m-2]...a[k+1]是a[m-1]...a[0]a[m-1]...a[0]的子串,所以我们只要把串a反一下,然后再扩展一倍,求出最小字典序的后缀就行了,这里要注意后缀的起始位置要大于0,小于m。

ps:这题不能用多组数据输入,会wa,也是醉了。


#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
#define lson th<<1
#define rson th<<1|1
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define maxn 400050
int sa[maxn],a[maxn],b[maxn],pos[maxn];
int wa[maxn],wb[maxn],wv[maxn],we[maxn];
int rk[maxn],height[maxn];
int cmp(int *r,int a,int b,int l){
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
void build_sa(int *r,int n,int m)
{
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0;i<m;i++)we[i]=0;
    for(i=0;i<n;i++)we[x[i]=r[i]]++;
    for(i=1;i<m;i++)we[i]+=we[i-1];
    for(i=n-1;i>=0;i--)sa[--we[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++)we[i]=0;
        for(i=0;i<n;i++)we[wv[i]]++;
        for(i=1;i<m;i++)we[i]+=we[i-1];
        for(i=n-1;i>=0;i--)sa[--we[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++;
    }
}

void calheight(int *r,int n)
{
    int i,j,k=0;
    for(i=1;i<=n;i++)rk[sa[i]]=i;
    for(i=0;i<n;height[rk[i++] ]=k){
        for(k?k--:0,j=sa[rk[i]-1];r[i+k]==r[j+k];k++);
    }
}

int calmin(int n)
{
    int minx=inf,i;
    int weizhi=-1;
    for(i=2;i<n;i++){
        if(rk[i]<minx){
            minx=rk[i];
            weizhi=i;
        }
    }
    return weizhi;
}
int c[maxn],cnt;
int d[maxn];

int main()
{
    int m,i,j,tot,n,weizhi,mm;
    scanf("%d",&n);
    tot=0;
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
        pos[++tot]=a[i];
    }
    sort(pos+1,pos+1+tot);
    tot=unique(pos+1,pos+1+tot)-pos-1;

    for(i=0;i<n;i++){
        a[i]=lower_bound(pos+1,pos+1+tot,a[i])-pos;
        b[n-1-i]=a[i];
    }
    b[n]=0;
    build_sa(b,n+1,200010);
    calheight(b,n);
    weizhi=calmin(n);

    cnt=0;
    for(i=weizhi;i<n;i++){
        c[cnt++]=pos[b[i] ];
    }

    m=0;
    for(i=0;i<weizhi;i++){
        d[m++]=b[i];
    }
    for(i=0;i<m;i++){
        d[i+m]=d[i];
    }
    mm=m*2;

    d[mm]=0;
    build_sa(d,mm+1,200010 );
    calheight(d,mm);

    int minx=inf;
    weizhi=-1;
    for(i=1;i<m;i++){
        if(rk[i]<minx){
            minx=rk[i];
            weizhi=i;
        }
    }
    for(i=weizhi;i<m;i++){
        c[cnt++]=pos[d[i] ];
    }
    for(i=0;i<weizhi;i++){
        c[cnt++]=pos[d[i] ];
    }

    for(i=0;i<cnt;i++){
        printf("%d\n",c[i]);
    }
}


你可能感兴趣的:(poj,后缀数组)