题面
略
分析
从小到大询问([1,i-1])与(i),若答案不为0,则(i)为第二个有磁性的磁体。找到这个磁体后,我们可以对(i)后面的位置和(i)单独询问,进而得到后面的所有磁性
然后在([1,i-1])中二分出第一个磁体的位置,剩下的都是没有磁性的。
总询问次数为(n-1+ lceil log_2 n ceil leq n+lfloor log_2 n floor)
代码
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int Ask(int fr,int ed,int pos){
int ans;
printf("? %d %d
",ed-fr+1,1);
for(int j=fr;j<=ed;j++) printf("%d ",j);
printf("
%d
",pos);
fflush(stdout);
scanf("%d",&ans);
return ans;
}
void print(vector<int>v){
printf("! %d
",(int)v.size());
for(int x : v) printf("%d ",x);
fflush(stdout);
}
int T,n;
int main(){
scanf("%d",&T);
while(T--){
vector<int>ans;
scanf("%d",&n);
for(int i=2;i<=n;i++){
if(Ask(1,i-1,i)!=0){//找到第2个有磁性的位置
//用这个磁体确定后面的磁性
for(int j=i+1;j<=n;j++) if(Ask(i,i,j)==0) ans.push_back(j);
int l=1,r=i-1,mid,pos=0;
while(l<=r){//找到第1个有磁性的位置
mid=(l+r)>>1;
if(Ask(1,mid,i)!=0){
pos=mid;
r=mid-1;
}else l=mid+1;
}
for(int j=1;j<pos;j++) ans.push_back(j);
for(int j=pos+1;j<i;j++) ans.push_back(j);
print(ans);
break;
}
}
}
}