suxxsfe

一言(ヒトコト)

CF744B Hongcow's Game

因为对角线上都是 \(0\),所以如果询问时包含了对角线,那结果必然是 \(0\),会对判断造成干扰
因此我们处理询问的结果时,如果当前这一行的处于对角线上的那一位,在询问时给出的 \(k\) 个数中,则应该忽略这一行结果(因为它是 \(0\)

所以,就要想办法让每一位不在对角线上的数,都在至少一次询问中,不和它那一行的对角线上的数同时出现
用二进制的想法考虑,因为任意一位不在对角线上的数,和那一行在对角线上的数的列号,都至少有一个二进制为相同
所以就枚举每一个二进制位,分别询问所有的在这个二进制位上是 \(0\)\(1\) 的列号
那么对于每个数,就都会在它和它那一行对角线的列号,的不同的那个二进制位被枚举时,产生有效的询问

话说这种思路好像还挺常见的,之前在 bzoj 某图论题(具体哪个忘了),好像就是用类似于 XX 和 XX 至少一个二进制位不同,来用二进制的思路优化的建边

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<map>
#include<iomanip>
#include<cstring>
#define reg register
#define EN puts("")
inline int read(){
	register int x=0;register int y=1;
	register char c=std::getchar();
	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
	return y?x:-x;
}
int a[1005];
int main(){
	int n=read();
	std::memset(a,0x3f,sizeof a);
	for(reg int cnt,i=0;i<10;i++){
		cnt=0;
		for(reg int j=1;j<=n;j++)if(j&(1<<i)) cnt++;
		if(!cnt) goto NEXT;
		printf("%d\n",cnt);
		for(reg int j=1;j<=n;j++)if(j&(1<<i)) printf("%d ",j);EN;
		std::fflush(stdout);
		for(reg int j=1;j<=n;j++){
			cnt=read();
			if(j&(1<<i)) continue;
			a[j]=std::min(a[j],cnt);
		}
		NEXT:;
		cnt=0;
		for(reg int j=1;j<=n;j++)if(!(j&(1<<i))) cnt++;
		if(!cnt) continue;
		printf("%d\n",cnt);
		for(reg int j=1;j<=n;j++)if(!(j&(1<<i))) printf("%d ",j);EN;
		std::fflush(stdout);
		for(reg int j=1;j<=n;j++){
			cnt=read();
			if(!(j&(1<<i))) continue;
			a[j]=std::min(a[j],cnt);
		}
	}
	puts("-1");
	for(reg int i=1;i<=n;i++) printf("%d ",a[i]);
	std::fflush(stdout);
	return 0;
}
posted @ 2020-09-15 22:16  suxxsfe  阅读(112)  评论(0编辑  收藏  举报