4278: [ONTAK2015]Tasowanie

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 290  Solved: 131
[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

[Submit][Status][Discuss]

-------------------

把两个串并起来 后缀数组搞一下

然后每次贪心选取字典序小的那个

每个串最后加一个 无穷大 因为如果两个串匹配到最后还没有出结果那么显然先选长的那个串

参照样例

代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define For(i,x,y) for(int i=x;i<=y;++i)
using namespace std;
const int N = 4e5+1000; 
//int a[N],b[N];
struct dat{
    int x,y,i;
    bool operator < (const dat&b)const{return x<b.x||x==b.x&&y<b.y;}
    bool operator != (const dat b){return x!=b.x||y!=b.y;}
}p[N];
int log[N];
    int n,m;int a[N*2];
    int rk[N*4],sa[N*2];
    void pre(){
        scanf("%d",&n);
        For(i,1,n) scanf("%d",&a[i]);
        a[n+1]=1e9;n++;
        scanf("%d",&m);
        For(i,1,m) scanf("%d",&a[i+n]);
        n+=m+1;m++;a[n]=1e9;
        For(i,1,n) rk[i]=a[i];
        For(j,0,log[n]){
            For(i,1,n) p[i]=(dat){rk[i],rk[i+(1<<j)],i};
            sort(p+1,p+n+1);
            int k=1;
            For(i,1,n){
                rk[p[i].i]=k;
                if(p[i]!=p[i+1])k++;
            }
        }
        For(i,1,n) sa[rk[i]]=i;
    }
 
int s[N];
int main(){
//  freopen("1.in","r",stdin);
    log[0]=-1;For(i,1,N-1) log[i]=log[i>>1]+1;
    pre();
    int t1=1,t2=n-m+1;
    For(i,1,n){
        if((t2>n)||(t1<=n-m&&rk[t1]<=rk[t2])) s[i]=a[t1++];
        else s[i]=a[t2++];
    }
    For(i,1,n-2) printf("%d ",s[i]);
}

 

 posted on 2017-02-17 20:17  rwy  阅读(153)  评论(0编辑  收藏  举报