Finding Zero
思路:刚拿到题目就看到最多提问2n-2次,仔细一想:如果能找到最大值,那么就可以花n-2次来找到0,原理很简单,遍历1 maxid i,不断更新max() - min()的最大值,最后得到一个下标ansid,可以知道0一定是在1或者ansid之中,直接输出即可。所以只需要花n次提问来找最大值,后面一直处理不好,结果第二天才解出来。
解释一下代码:刚开始花n-2次提问去找最大值的下标(选2个数不动,循环n-2次),得出来的maxid可能是0,可能是最大值,也可能是一个很特殊的值(既不是最大值也不是最小值,但是却能让max()-min()最大),所以maxid不一定是最大值下标,于是最后需要另外判断一下,第二次花n-2次提问1 maxid i去找最小值的下标,得到ansid,所以最大值和最小值就在 1 maxid ansid 之中,再花2次提问来排除那个中间值。
(小白的思路,可能讲的不是很清楚,下面代码有注解)
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
//cin.tie(0) , cout.tie(0);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int maxid = -1,x,maxx = -1;
for(int i=3;i<=n;i++){
cout<<"? "<<1<<" "<<2<<" "<<i<<endl;
cin>>x;
if(x > maxx){
maxx = x;
maxid = i;
}
}
//maxid 要么是最大值 要么是0 要么是一个很特殊的值
maxx = -1;
int ansid = -1;
for(int i=2;i<=n;i++){
if(i != maxid){
cout<<"? "<<1<<" "<<maxid<<" "<<i<<endl;
cin>>x;
if(x > maxx){
ansid = i;//如果maxid是0 那ansid就是最大值 maxid是最大值 ansid就是0
maxx = x;
}
}
}
//剩下 1 maxid ansid ,来判断一下哪个是中间值
//取一个无关变量testid
int testid = -1; //存一下用来测试的下标
if(maxid!=2 && ansid != 2){
cout<<"? "<<maxid<<" "<<ansid<<" "<<2<<endl;
testid = 2;
}
else if(maxid!=3 && ansid!=3){
cout<<"? "<<maxid<<" "<<ansid<<" "<<3<<endl;
testid = 3;
}
else if(maxid!=4 && ansid!=4){
cout<<"? "<<maxid<<" "<<ansid<<" "<<4<<endl;
testid = 4;
}
cin>>x;
if(x != maxx){ //如果maxid和ansid相减还不是最大值的话 说明下标1肯定是最大值最小值之一
cout<<"? "<<1<<" "<<maxid<<" "<<testid<<endl;
cin>>x;
if(x != maxx){ //如果1 和 maxid的差值还不是最大值的话 说明0就在ansid 和 1中
maxid = 1; //把maxid替换成1
}
else{
ansid = 1; //否则把ansid替换成1
}
}
cout<<"! "<<maxid<<" "<<ansid<<endl;
}
return 0;
}