AtCoder Regular Contest 154 D. A + B > C ?(交互 思维+排序)

题目

交互题,

每次给定一个数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;
}

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/128761950