[KTSC 2023 R1] 会议室

[KTSC 2023 R1] 会议室

我们不妨要求每次操作结束后,每个位置与相邻两个位置的数均不同。

考虑对于 \(u \not= v\) 且 \(v \not= w\),我们构造函数 \(f(x,y)\) 使得:

  • \(f(u,v) \not= f(v,w)\)

在 morning 函数中,我们需要构造这样的 \(f(v,w)\),不妨利用 \(v\) 和 \(w\) 之间的差异。我们令 \(v\) 和 \(w\) 在从小到大第 \(k\) 位不同,且 \(v\) 的第 \(k\) 位为 \(v_k\),定义 \(f(v,w) = 2k + v_k\)。

首先根据 \(f(v,w)\),我们能够得出 \(k\) 和 \(v_k\) 的值。此时有两种情况:

  • \(f(u,v)\) 和 \(f(v,w)\) 的 \(k\) 不同,则两者必然不同

  • \(f(u,v)\) 和 \(f(v,w)\) 的 \(k\) 相同,则 \(u_k\) 和 \(v_k\) 不同,两者必然不同

设值域为 \([0,V]\),则 \(k \leq \lfloor \log V \rfloor\),\(f\) 的值域为 \([0,2 \times \lfloor \log V \rfloor + 1]\)。

而我们在过程中总共可以进行 \(5\) 轮这样的变换,其中有 \(2\) 轮是通过预测得到的结果。

通过简单的计算得出,\(V=99999\) 会缩减成 \(33,11,7,5,5\),此时可以做到 \(m=6\)。

容易发现我们通过上面的 \(f\) 最多只能做到 \(m=6\),这启示我们寻找更牛的函数。

考虑先进行映射后再按上面的规律求 \(f(v,w)\),这里有一个不知道怎么想的:

  • 将 \(v\) 与所有 \(k\) 个 \(0\) 和 \(k\) 个 \(1\) 构成的二进制数进行映射

考虑此时的函数,我们可以考虑第一个不同的位,且 \(v\) 的该位为 \(1\),直接返回该位。

显然可以找到该位,且我们能够根据该函数区分,分析类似上面。

此时我们支持的原值域是 \([0,\dbinom{2k}{k}-1]\),这比原先的函数牛了一万倍。

计算出从 \(V=99999\) 会缩减成 \(19,5,3,3,3\),容易发现 evening 函数没有任何作用。

考虑在 evening 函数中将 \(3\) 变成 \([0,2]\) 中的数,显然没有两个相邻的 \(3\)。

也就是说,每个 \(3\) 都是独立的,找到相邻的两个之外的数即可。

#include<iostream>
#include<cstdio>
using namespace std;
int pop_count(int num){
	int sum=0;
	for(int i=0;i<20;i++){
		if(num&(1<<i)){
			sum++;
		}
	}
	return sum;
}
int f(int num1,int num2){
	for(int i=0;;i++){
		int cmd1=0,cmd2=0;
		if(num1&(1<<i)){
			cmd1=1;
		}
		if(num2&(1<<i)){
			cmd2=1;
		}
		if(cmd1  &&  !cmd2){
			return i;
		}
	}
}
int morning_1[200010],afternoon_1[200010],afternoon_2[200010];
void init(){
	int tot_morning_1=0;
	for(int i=0;i<(1<<20);i++){
		if(pop_count(i)==10){
			morning_1[tot_morning_1++]=i;
		}
	}
	int tot_afternoon_1=0;
	for(int i=0;i<(1<<6);i++){
		if(pop_count(i)==3){
			afternoon_1[tot_afternoon_1++]=i;
		}
	}
	int tot_afternoon_2=0;
	for(int i=0;i<(1<<4);i++){
		if(pop_count(i)==2){
			afternoon_2[tot_afternoon_2++]=i;
		}
	}
}
int morning(int my_num,int right_num){
	return f(morning_1[my_num],morning_1[right_num]);
}
int afternoon(int left_num,int my_num,int right_num){
	return f(afternoon_2[f(afternoon_1[my_num],afternoon_1[right_num])],afternoon_2[f(afternoon_1[left_num],afternoon_1[my_num])]);
}
int evening(int left_num,int my_num,int right_num){
	if(my_num!=3){
		return my_num;
	}
	else{
		if(left_num!=right_num) return 3-left_num-right_num;
		else return (left_num+1)%3;
	}
}
posted @ 2026-05-22 15:33  Oken喵~  阅读(19)  评论(0)    收藏  举报