因为对角线上都是 (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
",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
",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;
}