大意:
有一个0-n-1的排列,每次询问x,y会返回对应位置元素的gcd。
要求在n*2次询问内找到a,b,满足两个里面有一个位置的元素是0
思路:
想直接找到0的位置应该是不可能的,不然题目也不会放宽条件让你找两个数的。所以我们可以转换一下思路,看看有哪些位置一定不是0,这样的话就也就不用费心0的具体位置了。考虑三个数a,b,c,我们询问x=gcd(a,c),y=gcd(b,c),
那么会有以下三种情况:
x>y:这时我们可以说b一定不是0。如果b是0,则y=c,而x=gcd(a,c)<=c,这就互相矛盾了。
x<y:a一定不是0,理由同上
x=y:c一定不是0,因为a!=b。
如此,我们每选三个数,两次询问就可以排掉一个位置。要排掉n-2个位置,我们只用询问2n-4次就可以了。
code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
//#define endl '\n'
const ll N=1e5+10;
ll n,t;
ll a,b;//回答
void solve()
{
cin>>n;
ll l=1,r=2;
for(int i=3;i<=n;++i)
{
cout<<"? "<<l<<' '<<i<<endl;
cin>>a;
cout<<"? "<<r<<' '<<i<<endl;
cin>>b;
if(a==b);
else if(a>b) r=i;//l不是0,排除
else l=i;//r不是0,排除
}
cout<<"! "<<l<<" "<<r<<endl;
cin>>a;
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
cin>>t;
while(t--)
solve();
return 0;
}