题目
交互题,
每次给定一个数n(1<=n<=2e3),表明此时有一个长为n的排列p,
你可以最多询问25000次,每次询问,
输出三个允许重复的数i,j,k(1<=i,j,k<=n),
交互机会告诉你pi+pj>pk是否成立,成立返回Yes,否则返回No
所有询问后,你需要输出排列p
思路来源
灵茶群
题解
n<=2e3,q<=25000次,观察着比较像O(nlogn),
实际也是如此,做法就是nlogn+n的
1. 先通过n次询问找到1的位置,即遍历一遍,维护最小值,
询问2*pi>pmn是否成立,其中pmn是当前维护的最小值的下标
若不成立说明2*pi<=pmn,找到了一个新的最小值pmn
1出现的时候,pmn会被替代为1的位置,且后续不会再改变,所以一遍遍历可行
2. 根据1+pj>pk是否成立,来判断j和k的相对位置,
由于pj≠pk,所以若1+pj>pk成立说明pj>pk,否则pj<pk
作为sort函数的排序规则cmp函数即可,
sort函数,可能会因为随机轴的选取,量级虽然是O(nlogn),
但是常数上,实际次数会略微超限
所以,这里采用stable_sort函数,内部归并排序,稳定nlogn次
(感觉好像之前做过类似的排序)
代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2e3+10;
int n,mn=1,rk[N],a[N];
string s;
bool ask(int i,int j,int k){
cout<<"? "<<i<<" "<<j<<" "<<k<<endl;
cin>>s;
return s[0]=='Y';
}
int main(){
cin>>n;
for(int i=1;i<=n;++i){
//2*pi<=mn,mn=pi
rk[i]=i;
if(!ask(i,i,mn)){
mn=i;
}
}
stable_sort(rk+1,rk+n+1,[&](int x,int y){
return !ask(mn,x,y);
});
for(int i=1;i<=n;++i){
a[rk[i]]=i;
}
cout<<"!";
for(int i=1;i<=n;++i){
cout<<" "<<a[i];
}
cout<<endl;
return 0;
}