BZOJ4278 [ONTAK2015]Tasowanie[后缀数组+贪心]

题目

求两数组归并后的数组最小字典序排列。

嘛,可能本人在贪心这块还是太弱了(或者说什么都弱),如果不知道是字符串题估计也想不起来用sa。

显然看得出归并时字典序小的那个数组先往里面加,这就是要比较两数组后缀的rank,方法就把两串相拼做后缀排序后比较。

这里附下贪心正确性证明,反正我不太会,只是感性认识一下。

Upd:突然想起来这题其实可以hash+二分比较,码量稍小,不想写了

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 typedef pair<int,int> pii;
 5 template<typename T>inline char MIN(T&A,T B){return A<B?A=B,1:0;}
 6 template<typename T>inline char MAX(T&A,T B){return A>B?A=B,1:0;}
 7 template<typename T>inline T _min(T A,T B){return A<B?A:B;}
 8 template<typename T>inline T _max(T A,T B){return A>B?A:B;}
 9 template<typename T>inline T read(T&x){
10     x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1;
11     while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();return f?x=-x:x;
12 }
13 const int N=200000+7;
14 int A[N<<1],a[N],b[N],l,m,n;
15 
16 int rk[N<<1],sa[N<<1],cnt[N<<1],y[N<<1],t=1001,p;
17 inline void suffix_sort(){
18     for(register int i=1;i<=l;++i)++cnt[rk[i]=A[i]];
19     for(register int i=1;i<=t;++i)cnt[i]+=cnt[i-1];
20     for(register int i=l;i;--i)sa[cnt[A[i]]--]=i;
21     for(register int k=1;k<l;k<<=1,p=0){
22         for(register int i=l-k+1;i<=l;++i)y[++p]=i;
23         for(register int i=1;i<=l;++i)if(sa[i]>k)y[++p]=sa[i]-k;
24         for(register int i=1;i<=t;++i)cnt[i]=0;
25         for(register int i=1;i<=l;++i)++cnt[rk[y[i]]];
26         for(register int i=1;i<=t;++i)cnt[i]+=cnt[i-1];
27         for(register int i=l;i;--i)sa[cnt[rk[y[i]]]--]=y[i];
28         swap(rk,y);rk[sa[1]]=p=1;
29         for(register int i=2;i<=l;++i)rk[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i-1]+k]==y[sa[i]+k]?p:++p;
30         if(p==l)break;t=p;
31     }//for(register int i=1;i<=l;++i)printf("%d %d\n",i,rk[i]);
32 }
33 //
34 int main(){//freopen("tmp.in","r",stdin);freopen("tmp.out","w",stdout);
35     read(n);for(register int i=1;i<=n;++i)A[i]=read(a[i]);A[n+1]=1001;
36     read(m);for(register int i=1;i<=m;++i)A[n+i+1]=read(b[i]);A[n+m+2]=1001;
37     l=n+m+2;suffix_sort();int i=1,j=1;
38     while(i<=n||j<=m){
39         if(rk[i]<rk[n+j+1])printf("%d ",a[i++]);
40         else printf("%d ",b[j++]);
41     }puts("");
42     return 0;
43 }

 

posted @ 2019-02-08 08:54  Ametsuji_akiya  阅读(138)  评论(0编辑  收藏  举报