KOI TST 2023 Day1 T4 야유회

发布时间 2023-06-28 17:02:12作者: yyyyxh

KO Itst

神奇题。根本想不到。

题意

题意是你需要并行计算一个环的 k-coloring,初始时环上每个点的颜色被设置成它的标号(注意环上的标号被打乱了,并不连续),你需要实现三个函数:

  • \(\texttt{morning(m,r)}\):给定环上当前节点和当前节点的下一个节点的初始颜色 \(m,r\),返回当前节点的新的颜色,颜色标号需在 \([0,10^9]\) 范围内。
  • \(\texttt{afternoon(l,m,r)}\):给定环上当前节点的上一个,本身和下一个节点的被 \(\texttt{morning}\) 函数染上的颜色 \(l,m,r\),返回当前节点的新的颜色,颜色标号需在 \([0,10^9]\) 范围内。
  • \(\texttt{evening(l,m,r)}\):给定环上当前节点的上一个,本身和下一个节点的被 \(\texttt{afternoon}\) 函数染上的颜色 \(l,m,r\),返回当前节点的新的颜色,颜色标号需在 \([0,40]\) 范围内。

环长至多 \(10^5\),实现的函数只能与函数形参即 \(l,m,r\) 有关。执行完三轮后,相邻两个节点的最终被 \(\texttt{evening}\) 函数染上的颜色应不同,且不同颜色数目应该尽可能小。设用了 \(k\) 种不同颜色,\(k=3\) 可以拿满分。

思路

这道题要求我们不断的去压缩环上颜色标号的最大值。注意到一开始和最终都满足相邻两点颜色不同,我们考虑维持相邻两点颜色不同的不变式。

\(k=6\)

我们考虑先实现一个环上相邻两个颜色的压缩函数 \(f(x,y)\),这个函数有定义域 \(x\neq y\),要保证 \(f(x,y)\neq f(y,z)\)

人类智慧,考虑活用不变式 \(x\neq y\),我们找到二进制下 \(x,y\) 最高的不同位,然而只有这个信息很容易被 \(x=1,y=0,z=1\) 这种数据 hack 掉。

发现我们只需要再记录一个 \(x,y\) 的大小关系,那么如果 \(\text{highbit}(x \oplus y)=\text{highbit}(y \oplus z)\),一定有 \([x<y]\neq [y<z]\)

\(\texttt{morning}\) 调用一次可以到 \(k=34\),再在 \(\texttt{afternoon}\) 调用一次 \(k=8\)

注意到 \(\texttt{afternoon}\) 有三个参数,我们由于可以用 \(f(x,y)\neq f(y,z)\) 维持外层 \(f\) 的不变式,可以返回 \(f(f(x,y),f(y,z))\)。做到 \(k=6\),然而到了这种压缩方式的极限(\(2\lceil \log_2(n) \rceil\))了,所以 \(\texttt{evening}\) 相当于浪费。

\(k=4\)

考虑新的压缩方式,我们只要满足 \(f(x,y)\neq f(y,z)\),所以可以直接把值域中的每一个数压缩成长度为 \(T\) 只有 \(S\)\(1\) 的 01 串。返回 \(x\)\(1\)\(y\)\(0\) 的最高/低位
,由于 \(1\) 的个数相同所以这样的位一定存在。可以把 \({T\choose S}\) 的值域压到只有 \(T\)

仿照上面的方式,可以一路把 \(k\) 压到 \(k=4\)。然而 \(k=4\) 就又到了极限了。

\(k=3\)

发现我们的 \(\texttt{evening}\) 啥都没干,我们考虑最后如何将 \(k=4\) 压到 \(k=3\)

我们只修改颜色标号为 \(3\) 的位置,将它替换为 \(\neq l\)\(\neq r\) 的颜色即可。

代码

#include "workshop.h"
void GospersHack(int n,int k,int *arr){
    int cur=(1<<k)-1,cnt=0;
	while(cur<(1<<n)){
		arr[cnt++]=cur;
        int r=cur+(cur&-cur);
        cur=((r^cur)>>__builtin_ctz(cur)+2)|r;
    }
}
int f1[184756],f2[20],f3[6];
void init(){
	GospersHack(20,10,f1);
	GospersHack(6,3,f2);
	GospersHack(4,2,f3);
}
int F1(int x,int y){return __builtin_ctz(f1[x]&~f1[y]);}
int F2(int x,int y){return __builtin_ctz(f2[x]&~f2[y]);}
int F3(int x,int y){return __builtin_ctz(f3[x]&~f3[y]);}
int morning(int m,int r){return F1(m,r);}
int afternoon(int l,int m,int r){return F3(F2(l,m),F2(m,r));}
int evening(int l,int m,int r){
	if(m<=2) return m;
	for(int i=0;i<3;++i) if(i!=l&&i!=r) return i;
	return -1;
}