[ACNOI2022]王校长的构造

题目

题目背景
滴——🎵 滴——🎵 踹1叉!🎵 你真了不得🎵 黑题构造,难不住你🎵 杀出个王校长!🎵

题目描述
可见于校长的博客

思路

啥也不会,先考虑拿 m = 2 n + 1 m=2n+1 m=2n+1 部分分。手玩较小的情况,发现 n = 2 n=2 n=2 有解,并可由此得到所有 2 ∣ n 2\mid n 2n 。但 n = 1 n=1 n=1 n = 3 n=3 n=3 都无解。猜测 2 ∤ n 2\nmid n 2n 无解。赛时我就想不明白这是为什么,所以我就寄了 😓

事实上我们注意到:记 p i    ( 1 ⩽ i ⩽ 2 n ) p_i\;(1\leqslant i\leqslant 2n) pi(1i2n) 为,走完 [ i − 1 , i ] [i{-}1,i] [i1,i] 这一段之后,接下来应当走哪一段。最初 p i = i + 1 p_i=i+1 pi=i+1,特别地,令 p 2 n = 1 p_{2n}=1 p2n=1 。那么 a , b a,b a,b 之间建立虫洞,等价于交换 p a , p b p_a,p_b pa,pb 。最后 p i p_i pi 构成一个 置换,与 1 1 1 在同一置换环中的点会被走过。

那么 m = 2 n + 1 m=2n+1 m=2n+1 希求一个完整的偶长度置换环,然而 2 ∤ n 2\nmid n 2n 表明它是奇排列,于是寄了。

想到置换是比较关键的。话又说回来,当你意识到 “不可能死循环” 的时候,你就应该从置换的角度去思考了啊 😢

然后考虑 m ⩽ 8 m\leqslant 8 m8 这样的部分分。发现两侧都不被经过的点,可以任意配对,并且这样的点也只能内部匹配。

由此,我们按照左右两侧的需要被经过情况,分出四类点 N ( o n e ) , A ( l l ) , L ( e f t ) , R ( i g h t ) N(one),A(ll),L(eft),R(ight) N(one),A(ll),L(eft),R(ight) 。那么显然的, N N N N N N 配对, L L L R R R 配对, A A A A A A 配对。那么 N N N 类点就不必再考虑了。这是 简化问题 的方式。

于是剩下 A L R A L R A ALRALRA ALRALRA 之类的东西。如果 A A A 的数量是 4 4 4 的倍数,直接用 m = 2 n + 1 m=2n+1 m=2n+1 方案构造即可,因为此时 L R LR LR 相当于路上的小插曲。如果 A A A 的数量不是 4 4 4 的倍数,我们知道,关键矛盾在于逆序对奇偶性。那么大概需要一对 L R A A L R {\color{red}L}{\color{blue}R}AA{\color{blue}L}{\color{red}R} LRAALR,然后蓝配蓝、红配红。

画图可见,它的效果是内部一个置换环、外部一个置换环。手玩可知,只要两个环都存在 A A A,二者就可以被拼接起来。与之相对的,如果没有这样的 pattern \text{pattern} pattern 就无解。因为这是唯一拯救这罪恶的逆序对的方法。

当然上面只表明了有解,实际上构造解的方式很 s i m p l e \rm simple simple:只需找到 A L R A L R ALRALR ALRALR,除了 L R LR LR 按照之前所说的 pattern \text{pattern} pattern 连,再把 A A AA AA 连上就行。当然外面的 A A A 也可以在右。

代码

#include <cstdio>
#include <algorithm> // Almighty XJX yyds!!
#include <cstring> // oracle: ZXY yydBUS!!!
#include <cctype> // Huge Egg Dog ate me!!!
#include <cstdlib>
using llong = long long;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
# define rep0(i,a,b) for(int i=(a); i!=(b); ++i)
inline int readint(){
	int a = 0, c = getchar(), f = 1;
	for(; !isdigit(c); c=getchar()) if(c == '-') f = -f;
	for(; isdigit(c); c=getchar()) a = a*10+(c^48);
	return a*f;
}

const int MAXN = 200005;
bool vis[MAXN];	int match[MAXN];

int nxt[MAXN];
int main(){
	int n = readint(), m = readint(), cnta = 0;
	while(m--) vis[readint()] = true;
	{ // basic matching for 'N'
		int lstn = -1;
		for(int i=1; i<=(n<<1); ++i)
			if(!vis[i-1] && !vis[i]){ // 'N'
				if(!(~lstn)){ lstn = i; continue; }
				match[i] = lstn, match[lstn] = i, lstn = -1;
			}
			else if(vis[i-1] && vis[i]) ++ cnta;
		if(~lstn){ puts("No"); return 0; }
	}
	if((cnta&3) == 2){
		bool flag = false;
		rep(i,1,n<<1) if(vis[i-1] && vis[i]){ // 'A'
			int rig = i; while(rig <= (n<<1) &&
				vis[rig-1] && vis[rig]) ++ rig;
			int zuo[3] = {0,0,0};
			for(int j=i-1; j; --j)
				if(!vis[j-1] && vis[j]) zuo[2] = j;
				else if(vis[j-1] && !vis[j]){
					zuo[1] = j; break; // collected
				}
			if(!zuo[1]){ i = rig-1; continue; }
			for(int j=zuo[1]-1; j; --j)
				if(vis[j-1] && vis[j]){
					zuo[0] = j; break;
				}
			int you[3] = {i,i,i};
			for(int j=i+1; j<=(n<<1); ++j)
				if(vis[j-1] && !vis[j]) you[0] = j;
				else if(!vis[j-1] && vis[j]){
					you[1] = j; break;
				}
			if(you[1] != i)
				for(int j=you[1]+1; j<=(n<<1); ++j)
					if(vis[j-1] && vis[j]){
						you[2] = j; break;
					}
			if(zuo[0] && you[1] != i){ // link to left
				match[zuo[0]] = i, match[i] = zuo[0];
				match[zuo[1]] = you[1], match[you[1]] = zuo[1];
				match[zuo[2]] = you[0], match[you[0]] = zuo[2];
				flag = true; break;
			}
			if(zuo[1] && you[2] != i){ // link to right
				match[rig-1] = you[2], match[you[2]] = rig-1; 
				match[zuo[1]] = you[1], match[you[1]] = zuo[1];
				match[zuo[2]] = you[0], match[you[0]] = zuo[2];
				flag = true; break;
			}
			i = rig-1; // skip the segment
		}
		if(!flag){ puts("No"); return 0; }
	}
	int lstl = -1, lsta[4] = {-1,-1,-1,-1};
	puts("Yes"); // can be sure
	for(int i=1|(cnta=0); i<=(n<<1); ++i){
		if(match[i]){
			if(match[i] < i)
				printf("%d %d\n",match[i],i);
			continue; // 'N' or known
		}
		if(vis[i-1] && vis[i]){ // 'A'
			lsta[cnta++] = i;
			if(cnta == 4){ // done
				printf("%d %d\n%d %d\n",lsta[0],
				  lsta[2],lsta[1],lsta[3]);
				cnta = 0; // reset
			}
		}
		else if(vis[i-1]) // 'L'
			lstl = i; // assert(lstl == -1);
		else printf("%d %d\n",lstl,i);
	}
	return 0;
}

  1. 作词者 Rainybunny \textsf{Rainybunny} Rainybunny,意即 XY \text{XY} XY,叉歪。 ↩︎

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
4S店客户管理小程序-毕业设计,基于微信小程序+SSM+MySql开发,源码+数据库+论文答辩+毕业论文+视频演示 社会的发展和科学技术的进步,互联网技术越来越受欢迎。手机也逐渐受到广大人民群众的喜爱,也逐渐进入了每个用户的使用。手机具有便利性,速度快,效率高,成本低等优点。 因此,构建符合自己要求的操作系统是非常有意义的。 本文从管理员、用户的功能要求出发,4S店客户管理系统中的功能模块主要是实现管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理,用户客户端:首页、车展、新闻头条、我的。门店客户端:首页、车展、新闻头条、我的经过认真细致的研究,精心准备和规划,最后测试成功,系统可以正常使用。分析功能调整与4S店客户管理系统实现的实际需求相结合,讨论了微信开发者技术与后台结合java语言和MySQL数据库开发4S店客户管理系统的使用。 关键字:4S店客户管理系统小程序 微信开发者 Java技术 MySQL数据库 软件的功能: 1、开发实现4S店客户管理系统的整个系统程序; 2、管理员服务端;首页、个人中心、用户管理、门店管理、车展管理、汽车品牌管理、新闻头条管理、预约试驾管理、我的收藏管理、系统管理等。 3、用户客户端:首页、车展、新闻头条、我的 4、门店客户端:首页、车展、新闻头条、我的等相应操作; 5、基础数据管理:实现系统基本信息的添加、修改及删除等操作,并且根据需求进行交流信息的查看及回复相应操作。
现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本微信小程序医院挂号预约系统就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此微信小程序医院挂号预约系统利用当下成熟完善的SSM框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。微信小程序医院挂号预约系统有管理员,用户两个角色。管理员功能有个人中心,用户管理,医生信息管理,医院信息管理,科室信息管理,预约信息管理,预约取消管理,留言板,系统管理。微信小程序用户可以注册登录,查看医院信息,查看医生信息,查看公告资讯,在科室信息里面进行预约,也可以取消预约。微信小程序医院挂号预约系统的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值