bzoj 4278 [ONTAK2015]Tasowanie

给出两个字符串 A B 让我们对其二路归并 求出能够归并出的最小字典序。

考虑后缀数组 不难发现我们将B直接连在A上会出现问题 问题是 A串剩下的和B串完全相同了 那么此时比大小就会用到B的部分 这是不合理的。

考虑怎么解决这个问题 如果比到了末尾之后的数字 那么较长的串答案不会更差 所以考虑在中间加一个INF.

对于B也有这种情况 那么需要在末尾也加一个INF 即可解决问题 可以证明这样做是最优的。

具体的 可以这样思考 我们之所以让较长的优先 是考虑到了较长的第一个决定字典序的位置上的字符 其如果比当前参与比较的都大 那么不管优不优先对结果没有影响 反之必然更优。

//#include<bitsstdc++.h>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<cctype>
#include<cstdlib>
#include<queue>
#include<deque>
#include<stack>
#include<vector>
#include<algorithm>
#include<utility>
#include<bitset>
#include<set>
#include<map>
#define ll long long
#define db double
#define INF 10000000000000000ll
#define ld long double
#define pb push_back
#define get(x) x=read()
#define gt(x) scanf("%d",&x)
#define put(x) printf("%d
",x)
#define putl(x) printf("%lld
",x)
#define gc(a) scanf("%s",a+1);
#define rep(p,n,i) for(RE int i=p;i<=n;++i)
#define go(x) for(int i=lin[x],tn=ver[i];i;tn=ver[i=nex[i]])
#define fep(n,p,i) for(RE int i=n;i>=p;--i)
#define pii pair<int,int> 
#define F first
#define S second
#define mk make_pair
#define P 13331ll
#define mod 1000003
#define RE register
#define gf(x) scanf("%lf",&x)
#define pf(x) ((x)*(x))
#define ull unsigned long long
using namespace std;
char buf[1<<15],*fs,*ft;
inline char getc()
{
	return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
}
inline int read()
{
	RE int x=0,f=1;char ch=getc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getc();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getc();}
	return x*f;
}
const int MAXN=200010<<2;
int n1,n2,n,m;
int a[MAXN],sa[MAXN],rk[MAXN],x[MAXN],y[MAXN],c[MAXN];
inline void SA()
{
	m=1001;
	rep(1,n,i)++c[x[i]=a[i]];
	rep(1,m,i)c[i]+=c[i-1];
	fep(n,1,i)sa[c[x[i]]--]=i;
	for(int k=1;k<=n;k=k<<1)
	{
		int num=0;
		rep(n-k+1,n,i)y[++num]=i;
		rep(1,n,i)if(sa[i]>k)y[++num]=sa[i]-k;
		rep(1,m,i)c[i]=0;
		rep(1,n,i)++c[x[i]];
		rep(1,m,i)c[i]+=c[i-1];
		fep(n,1,i)sa[c[x[y[i]]]--]=y[i];
		rep(1,n,i)y[i]=x[i],x[i]=0;
		x[sa[1]]=num=1;
		rep(2,n,i)x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?num:++num;
		if(num==n)break;
		m=num;
	}
	rep(1,n,i)rk[sa[i]]=i;
}
int main()
{
	freopen("1.in","r",stdin);
	get(n1);
	rep(1,n1,i)get(a[i]);
	a[n1+1]=1001;
	get(n2);
	rep(1,n2,i)get(a[n1+1+i]);
	n=n1+1+n2+1;a[n]=1001;
	SA();
	int i=1,j=n1+2,w=n1+n2;
	while(w)
	{
		if(j>=n||rk[i]<rk[j])printf("%d ",a[i]),++i;
		else printf("%d ",a[j]),++j;
		--w;
	}
	return 0;
}
原文地址:https://www.cnblogs.com/chdy/p/12583987.html