input:
2
2
1
1
5
2
4
1
output:
? 1 2
! 1 2
? 1 2
? 2 3
! 3 3
题目大意:有一个长度为n的序列,其为0~n-1的全排列,但是你并不知道这个排列具体是什么,现在你可以进行询问,每次询问两个数的gcd的值,最多询问2n次,最终你要确定0可能存在的位置以‘!x y’的形式输出,只要x,y的位置上有一个是0就算猜对。
解题思路:
每次取3个位置上的数x,y,z,然后询问ans1=gcd(x,y),ans2=gcd(y,z)的值,如果gcd(x,y)==gcd(y,z),那么我们可以确定y一定不是0,因为如果y=0,那么gcd(x,y)=x,gcd(y,z)=z,x!=z,如果ans1>ans2,可以确定z一定不是0,因为如果z=0,那么ans2=y,ans1<=y,同理可得如果ans1<ans2,就可以确定x一定不是0,所以我们没两次询问就可以将一个位置排除,也就是说排除的这个位置一定不可能是0,那么当我们最后只剩下2个位置的时候直接输出两个位置的坐标就可以了。
#include <iostream>
#include <cstring>
#include <bits/stdc++.h>
using namespace std;
int t,n;
int main()
{
cin>>t;
while(t--)
{
cin>>n;
queue<int>q;
for(int i=1;i<=n;i++)
q.push(i);
while(q.size()>2)
{
int x,y,z;
x=q.front();
q.pop();
y=q.front();
q.pop();
z=q.front();
q.pop();
cout<<"?"<<" "<<x<<" "<<y<<endl;
int gcd1;
cin>>gcd1;
cout<<"?"<<" "<<y<<" "<<z<<endl;
int gcd2;
cin>>gcd2;
if(gcd1==gcd2)
{
q.push(x);
q.push(z);
}
else if(gcd1>gcd2)
{
q.push(x);
q.push(y);
}
else
{
q.push(y);
q.push(z);
}
}
int ans1,ans2;
ans1=q.front();
q.pop();
ans2=q.front();
q.pop();
cout<<"!"<<" "<<ans1<<" "<<ans2<<endl;
int ans;
cin>>ans;
}
return 0;
}