把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ4278】[ONTAK2015] Tasowanie(后缀数组+贪心)

点此看题面

大致题意: 给定两个数字串,让你对它们进行归并得到一个字典序最小的新串。

贪心

一看完题面首先想到无脑贪心,优先选小的数。

然后突然想到碰到两个一样的数该先选谁?于是无脑贪心就被\(Hack\)掉了。

所以,我们来考虑有脑贪心。

考虑先把两个串并起来后缀排序,则我们优先选择后缀排序中后缀排名较为靠前(即\(rk\)较小)的数即可。

至于正确性我想应该显然。

注意每个串最后要放一个大数(可以分别放上\(1001\)\(1002\)),不然样例都过不了。

代码

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 200000
using namespace std;
int n,m,s[2*N+5];
class FastIO
{
	private:
		#define FS 100000
		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
		#define pc(c) (C==E&&(clear(),0),*C++=c)
		#define D isdigit(c=tc())
		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
	public:
		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
		Tp I void write(Con Ty& x,Con char& y) {write(x),pc(y);}
		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
class SuffixArray//后缀数组
{
	private:
		int n,SA[2*N+5],p[2*N+5],t[2*N+5];
		I void Sort(CI S)
		{
			RI i;for(i=0;i<=S;++i) t[i]=0;for(i=1;i<=n;++i) ++t[rk[i]];
			for(i=1;i<=S;++i) t[i]+=t[i-1];for(i=n;i;--i) SA[t[rk[p[i]]]--]=p[i];
		}
	public:
		int rk[2*N+5];
		I void GetSA(CI x,int *s)
		{
			RI i;for(n=x,i=1;i<=n;++i) rk[p[i]=i]=s[i];
			RI k,t=0,S=1002;for(Sort(S),k=1;t^n;S=t,k<<=1)
			{
				for(t=0,i=1;i<=k;++i) p[++t]=n-k+i;
				for(i=1;i<=n;++i) SA[i]>k&&(p[++t]=SA[i]-k);
				for(Sort(S),i=1;i<=n;++i) p[i]=rk[i];
				for(rk[SA[1]]=t=1,i=2;i<=n;++i)
					rk[SA[i]]=(p[SA[i-1]]^p[SA[i]]||p[SA[i-1]+k]^p[SA[i]+k])?++t:t;
			}
		}
}S;
int main()
{
	RI i,j;for(F.read(n),i=1;i<=n;++i) F.read(s[i]);s[n+1]=1001;
	for(F.read(m),i=1;i<=m;++i) F.read(s[n+1+i]);s[n+m+2]=1002;S.GetSA(n+m+2,s);
	i=1,j=1;W(i<=n&&j<=m) F.write(S.rk[i]<S.rk[n+1+j]?s[i++]:s[n+1+(j++)],' ');//归并
	W(i<=n) F.write(s[i]," \n"[i==n]),++i;W(j<=m) F.write(s[n+1+j]," \n"[j==m]),++j;//处理剩余部分
	return F.clear(),0;
}
posted @ 2020-05-19 09:27  TheLostWeak  阅读(107)  评论(0编辑  收藏  举报