RedLycoris
2022-02-11 13:57:55
Warning:可能比官方题解复杂的多,思维难度估计要上紫,但推出来了能有很好的训练效果
令
这个方法的大体思路就是,通过两次全数组的询问,得到两个数的位置(
我们考虑这么询问:
固定前两个数
然后固定
显然,
然后我们来想,如何利用
我赛时的注释:
//now if both x[1] and x[2] isn't 0 this is okay
//if x[2] is 0? what will happen?
//a[i] will be x[i]. How to ensure it?
//we can ask(2,pos1,pos2) to check
//if x[1] is 0: it is smaller than either a[pos1] or a[pos2] we can return [1,1]
//if x[2] is 0: this returns a[pos1 or pos2] then we can return [2,pos1 or pos2]
//otherwise we can return [pos1,pos2]
//oops,there still can be x[1] is max and pos1 is zero
我们要分类讨论(如何判断是哪一类待会儿讲):
显然,对于这种情况,我们求得的
然后第二遍询问,因为询问的东西带上了
我们的
有可能
询问
如果说,
通过不断的尝试,我发现此时询问
我们令这次询问的返回值为
注意,一个是严格小于,另一个是小于等于。
这种情况对应了
两者的区别就在于,一个是
然而,此时的
然后到了这里,我们似乎发现了一个漏洞:
但这里我们之前已经排除这种情况了(
但上述讨论都是基于
通过比较
同理,上传
平凡情况,上传
次数:
询问次数为
code:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define reg register
const int mxn=1e3+3;
int n;
int a[mxn],b[mxn];
inline int ask(int x,int y,int z){
cout<<"? "<<x<<' '<<y<<' '<<z<<endl;
fflush(stdout);
int rt;cin>>rt;
return rt;
}
inline void print(int x,int y){
cout<<"! "<<x<<' '<<y<<endl;
fflush(stdout);
return;
}
inline void solve(){
cin>>n;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
int pos1=1;
int allsame=1;
int lst=-1;
for(int i=3;i<=n;++i){
a[i]=ask(1,2,i);
if(a[i]>a[pos1])pos1=i;
if(lst==-1)lst=a[i];
else{
if(a[i]!=lst){
lst=a[i];
allsame=0;
}
}
}
int allsame2=1,lst2=-1;
int pos2=1;
for(int i=2;i<=n;++i){
if(i==pos1)continue;
b[i]=ask(1,i,pos1);
if(b[i]>=b[pos2])pos2=i;
if(lst2==-1)lst2=b[i];
else if(lst2!=b[i])allsame2=0;
}
if(pos2==2)++pos2; //当n较小的时候可能会出现pos2=2的阴间情况,需手动更改
if(pos2==pos1)++pos2;
if(allsame==1){//this can all be x[1]-x[2]
int t=ask(1,pos1,pos2);
if(t<lst){
print(1,2);
return;
}
}
//now if both x[1] and x[2] isn't 0 this is okay
//if x[2] is 0? what will happen?
//a[i] will be x[i]. How to ensure it?
//we can ask(2,pos1,pos2) to check
//if x[1] is 0: it is smaller than either a[pos1] or a[pos2] we can return [1,1]
//if x[2] is 0: this returns a[pos1 or pos2] then we can return [2,pos1 or pos2]
//otherwise we can return [pos1,pos2]
//oops,there still can be x[1] is max and pos1 is zero
if(allsame2==1){
print(1,pos1);
return;
}
int t=ask(2,pos1,pos2);
if((t<a[pos1] and t<=a[pos2]) or (t<=a[pos1] and t<a[pos2])){
print(1,2);
return;
}
if(t==a[pos1]){
print(2,pos1);
return;
}
if(t==a[pos2]){
print(2,pos2);
return;
}
print(pos1,pos2);
return;
}
int main(){
int T=1;
cin>>T;
for(;T--;)solve();
return 0;
}