【BZOJ-4278】Tasowanie 后缀数组 + 归并

4278: [ONTAK2015]Tasowanie

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 164  Solved: 80
[Submit][Status][Discuss]

Description

给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T。

Input

第一行包含一个正整数n(1<=n<=200000),表示A串的长度。
第二行包含n个正整数,其中第i个数表示A[i](1<=A[i]<=1000)。
第三行包含一个正整数m(1<=m<=200000),表示B串的长度。
第四行包含m个正整数,其中第i个数表示B[i](1<=B[i]<=1000)。

Output

输出一行,包含n+m个正整数,即字典序最小的T串。

Sample Input

6
1 2 3 1 2 4
7
1 2 2 1 3 4 3

Sample Output

1 1 2 2 1 2 3 1 2 3 4 3 4

HINT

Source

By Claris

Solution

一眼秒后缀数组裸题?算出rank数组来

二路归并的输出答案即可....

PS感觉Claris不会传裸题上来的,于是%了发他的做法,是个贪心

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
#define maxn 400010
int len,val[maxn];
int S[maxn]; int SA[maxn];
int ws[maxn],wa[maxn],wv[maxn],wb[maxn];
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)
{
    int p,*x=wa,*y=wb,*t;
    for (int i=0; i<m; i++) ws[i]=0;
    for (int i=0; i<n; i++) ws[x[i]=r[i]]++;
    for (int i=1; i<m; i++) ws[i]+=ws[i-1];
    for (int i=n-1; i>=0; i--) sa[--ws[x[i]]]=i;
    p=1; for (int j=1; p<n; j*=2,m=p)
        {
            p=0; for (int i=n-j; i<n; i++) y[p++]=i;
            for (int i=0; i<n; i++) if (sa[i]>=j) y[p++]=sa[i]-j;
            for (int i=0; i<n; i++) wv[i]=x[y[i]];
            for (int i=0; i<m; i++) ws[i]=0;
            for (int i=0; i<n; i++) ws[wv[i]]++;
            for (int i=1; i<m; i++) ws[i]+=ws[i-1];
            for (int i=n-1; i>=0; i--) sa[--ws[wv[i]]]=y[i];
            t=x; x=y; y=t; p=1; x[sa[0]]=0;
            for (int i=1; i<n; i++) 
                x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
        } 
}
int rank[maxn],height[maxn];
void calheight(int *r,int *sa,int n)
{
    int k=0;
    for (int i=1; i<=n; i++) rank[sa[i]]=i;
    for (int i=0; i<n; height[rank[i++]]=k)
        {k?k--:0;for (int j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++);}
}
int N,M;
int main()
{
    N=read();
    for (int i=0; i<N; i++) S[i]=read(); S[N]=1001;
    M=read();
    for (int i=1; i<=M; i++) S[i+N]=read(); S[N+M+1]=0;
    DA(S,SA,N+M+2,1002); calheight(S,SA,N+M+1); 
    int a=0,b=N+1;
    for (int i=0; i<=N+M; i++)
        {
            if (i==N) continue;
            if (a==N) {for (int j=b; j<=N+M; j++) printf("%d ",S[j]); break;} 
            if (b==N+M+1) {for (int j=a; j<N; j++) printf("%d ",S[j]); break;}
            if (rank[a]<rank[b]) printf("%d ",S[a]),a++;
                else printf("%d ",S[b]),b++;
        }
    return 0;
}

跑得怎么比hs(hen)y快这么多..但还是被卡第一页了....

posted @ 2016-05-12 21:41  DaD3zZ  阅读(338)  评论(0编辑  收藏  举报