题意:

\(2n\)个位置,给长度为\(2n\)的序列A,B。问每一位置在\(A\)\(B\)中任选一个,恰好\(n\)个A和B,得到不降的序列\(C\)的方案(多种任意输出一种)。

思路:

  • 引理
    猜了一个结论:能够造出C的A的个数是连续的。
    和CF之前打过一道题,一样的技巧。
    这里给简略构造证明:
    处理出A个数最少(Amin个)的序列C1,和A最大(Amax个)的序列C2。
    考虑一步一步把C1变为C2。
    归纳法:考虑前\(i-1\)位已经每位对上了,现在对第\(i\)位,一共有四种情况发现都能无后效性地匹配成功。(自己画一下……)
    每一次相当于A个数+1(-1),B个数-1(+1)
    因此在Amin到Amax中间个数的A一定也能构造出来。
  • 构造
    先用求\(mx/mn[i][0/1]\):表示第\(i\)位选\(A/B\),A的个数max/min值。
    然后通过\(n\)是否包含于\([mn[n][0/1],mx[n][0/1]]\)判有无解。
    从后往前构造(因为dp存的是前缀信息),记录\(lst\)表示上一个填的数值,\(cnta\)表示当前需要的A的个数。
    因为我们判了,就保证至少有一个解。
    如果恰好只能填A/B中的一个(其中一个值比\(lst\)大),就直接填。
    两个都行,就用引理判断一下即可。

code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
const int inf=1e9;
int n,nn,a[N],b[N],mx[N][2],mn[N][2],Mx[N],Mn[N];
void DP() {
	for(int i=1;i<=nn;i++) {
		if(a[i-1]<=a[i]) mx[i][0]=mx[i-1][0]+1;
		if(b[i-1]<=a[i]) mx[i][0]=max(mx[i][0],mx[i-1][1]+1);
		if(a[i-1]<=b[i]) mx[i][1]=mx[i-1][0];
		if(b[i-1]<=b[i]) mx[i][1]=max(mx[i][1],mx[i-1][1]);
//		printf("i=%d :  mx[i][0]=%d mx[i][1]=%d\n",i,mx[i][0],mx[i][1]);
		Mx[i]=max(mx[i][0],mx[i][1]);
	}
	for(int i=1;i<=nn;i++) {
		mn[i][0]=mn[i][1]=inf;
		if(a[i-1]<=a[i]) mn[i][0]=mn[i-1][0]+1;
		if(b[i-1]<=a[i]) mn[i][0]=min(mn[i][0],mn[i-1][1]+1);
		if(a[i-1]<=b[i]) mn[i][1]=mn[i-1][0];
		if(b[i-1]<=b[i]) mn[i][1]=min(mn[i][1],mn[i-1][1]);
//		printf("i=%d :  mn[i][0]=%d mn[i][1]=%d\n",i,mn[i][0],mn[i][1]);
		Mn[i]=min(mn[i][0],mn[i][1]);
	}
}

char pth[N];
void solve() {
//	printf("%d %d\n",Mn[nn],Mx[nn]);
	if(Mn[nn]>n||Mx[nn]<n) {printf("-1");return;}
	
	int cnta=n,lst=inf;
	for(int i=nn;i;i--) {
		if(a[i]>lst) {pth[i-1]='B';lst=b[i];}
		else if(b[i]>lst) {pth[i-1]='A';cnta--;lst=a[i];}
		else {
//			printf("i=%d: *%d [%d,%d]\n",i,cnta,Mn[i-1],Mx[i-1]);
			if(mn[i][0]<=cnta&&cnta<=mx[i][0]) {cnta--;pth[i-1]='A';lst=a[i];}
			else {pth[i-1]='B';lst=b[i];}
		}
	}
	printf("%s",pth);
}
int main() {
//	freopen("build.in","r",stdin);
//	freopen("build.out","w",stdout);
	scanf("%d",&n);nn=n<<1;
	for(int i=1;i<=nn;i++)scanf("%d",&a[i]);
	for(int i=1;i<=nn;i++)scanf("%d",&b[i]);
	DP();
	solve();
	return 0;
}