Description
给定两个数字串A和B,通过将A和B进行二路归并得到一个新的数字串T,请找到字典序最小的T。
Input
第一行包含一个正整数n(1<=n<=200000),表示A串的长度。
第二行包含n个正整数,其中第i个数表示Ai。
第三行包含一个正整数m(1<=m<=200000),表示B串的长度。
第四行包含m个正整数,其中第i个数表示Bi。
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
题解
Orz YZH
在YZH大神的指导下,本蒟蒻终于AC了,YZH大神实在是太强了!!!!
比较两个数组的后缀数组大小,肯定是取rk小的。
代码
#include<bits/stdc++.h>
#define ll long long
#define inf 1000000000
#define mod 1000000007
using namespace std;
inline 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;
}
const int N=2333333;//Orz YZH
int n,m,tot,ans[N],rk[N],sa[N];
int sta[N],stb[N],tsa[N];
int a[N],b[N],A[N],B[N];
void SA(int n)
{
for (int i=1;i<=n;i++) sta[rk[i]]++;
for (int i=1;i<=1001;i++) sta[i]+=sta[i-1];
for (int i=n;i;i--) sa[sta[rk[i]]--]=i;
rk[sa[1]]=1;
for (int i=2;i<=n;i++)rk[sa[i]]=rk[sa[i-1]]+(rk[sa[i-1]]!=rk[sa[i]]);
for (int L=1;rk[sa[n]]!=n;L<<=1)
{
for (int i=0;i<=n;i++) sta[i]=stb[i]=0;
for (int i=1;i<=n;i++) A[i]=rk[i],B[i]=rk[i+L];
for (int i=1;i<=n;i++) sta[A[i]]++,stb[B[i]]++;
for (int i=1;i<=n;i++) sta[i]+=sta[i-1],stb[i]+=stb[i-1];
for (int i=n;i;i--) tsa[stb[B[i]]--]=i;
for (int i=n;i;i--) sa[sta[A[tsa[i]]]--]=tsa[i];
rk[sa[1]]=1;
for (int i=2;i<=n;i++)rk[sa[i]]=rk[sa[i-1]]+(A[sa[i-1]]!=A[sa[i]]||B[sa[i-1]]!=B[sa[i]]);
}
}
int main()
{
n=read();
for (int i=1;i<=n;i++) a[i]=rk[i]=read();rk[n+1]=1001;n++;
m=read();
for (int i=1;i<=m;i++) b[i+n]=rk[i+n]=read();b[n+m+1]=rk[n+m+1]=1001;m++;
SA(n+m);
int i=1,j=n+1;
while (i<n&&j<n+m)
{
if (rk[i]<rk[j]) ans[++tot]=a[i++];else ans[++tot]=b[j++];
}
while (i<n) ans[++tot]=a[i++];
while (j<n+m) ans[++tot]=b[j++];
for (int i=1;i<=tot;i++) printf("%d ",ans[i]);
return 0;
}