4278: [ONTAK2015]Tasowanie
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 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
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
-------------------
把两个串并起来 后缀数组搞一下
然后每次贪心选取字典序小的那个
每个串最后加一个 无穷大 因为如果两个串匹配到最后还没有出结果那么显然先选长的那个串
参照样例
代码:
#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]); }