ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

「JOISC 2020 Day1」建筑装饰 4

2022-07-15 20:32:15  阅读:212  来源: 互联网

标签:cnta int mn 个数 Day1 JOISC lst 2020 Mx


题意:

\(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;
}

标签:cnta,int,mn,个数,Day1,JOISC,lst,2020,Mx
来源: https://www.cnblogs.com/bestime/p/16482714.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有