NEERC 17 I Interactive Sort (交互题)

题意:

       给出1到n这n个数的任意一个排列,然后奇数按顺序分到o数组,偶数按顺序分到e数组,你每次可以询问e数组中第i个和o数组中第j个的大小情况,查询结束后输出结果,查询次数最多30 000次, n 1000

思路:

       我们先想,如果e是有序的,那么我们就可以枚举奇数组中每个数字,然后每次都二分,次数为 O ( n l o g n ) 。但是此时e是无序的,所以我们要想办法让e变得有序来减少询问次数。
        我们先用o数组中的数 x ,和e数组中每个数字比较关系,查询 n / 2 次,会发现,我们不仅确定了这个数字的大小,也将e数组切成了两块(一块里面的数字都比x小,一块里面数字都比x大,块内数字无序)。
        按照这个方法接着向下做,我们会发现,对于每个奇数,我们能利用这个奇数把某一个偶数块切成两块,这样我们最后会把偶数切成n/2块,也就确定了每个偶数的大小。这样我们就能 O ( n 2 ) 枚举得到结果。
       可是询问次数不允许,我们不能 O ( n 2 ) 枚举。我们发现偶数块其实也是具有一定的单调性的(虽然内部无序),我们可以用偶数块中某一个数字代表这个块,每次奇数查询的时候利用这个数字进行二分,二分就可以找到第一个代表值大于当前奇数的偶数块,这块以及前面一块都是有可能的(因为块内部是无序的),然后遍历两个块才能判断出到底需要的是哪一块。
       这种做法最差情况下询问次数是 O ( n 2 ) 的,但是题目保证数据是随机的,所以可以当作是 O ( n l o g n ) 的,而且因为n才1000,时间却有10秒,所以怎么随意暴力都是可以的

错误及反思:

       边界处理需要特判

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 11000;
int ans1[N],ans2[N],n,tot=1;
vector<int> v[N];

int change(int p,int x){
    int ans=0;

    for(int i=1;i<p;i++)
        ans+=v[i].size();

    vector<int> vv[2];

    for(int i=0;i<v[p].size();i++){
        printf("? %d %d\n",v[p][i],x);
        fflush(stdout);
        char t[10]; scanf("%s",t);
        if(t[0]=='<'){
            ans++;
            vv[0].push_back(v[p][i]);
        }
        else vv[1].push_back(v[p][i]);
    }

    if(vv[0].size()&&vv[1].size()){
        tot++;
        for(int i=tot;i>p;i--) v[i]=v[i-1];
        v[p]=vv[0];
        v[p+1]=vv[1];
    }
    else if(vv[1].size()==0){
        return n%2?n:n-1;
    }
    else if(p==1){
        return 1;
    }
    else{
        p--;

        ans=0;
        vv[0].clear(); vv[1].clear();
        for(int i=1;i<p;i++)
            ans+=v[i].size();

        for(int i=0;i<v[p].size();i++){
            printf("? %d %d\n",v[p][i],x);
            fflush(stdout);
            char t[10]; scanf("%s",t);
            if(t[0]=='<'){
                ans++;
                vv[0].push_back(v[p][i]);
            }
            else vv[1].push_back(v[p][i]);
        }

        tot++;
        for(int i=tot;i>p;i--) v[i]=v[i-1];
        v[p]=vv[0];
        v[p+1]=vv[1];
    }
    return ans*2+1;
}

int main(){
    scanf("%d",&n);
    if(n==1){
        puts("! 1\n");
        fflush(stdout);
        return 0;
    }
    if(n==2){
        puts("! 2 1\n");
        fflush(stdout);
        return 0;
    }
    for(int i=1;i<=n/2;i++) v[1].push_back(i);

    for(int i=1;i<=(n+1)/2;i++)
    {
        int l=0,r=tot;
        while(l+1<r){
            int m=(l+r)/2;
            printf("? %d %d\n",v[m][0],i);
            fflush(stdout);
            char t[10]; scanf("%s",t);
            if(t[0]=='<') l=m;
            else r=m;
        }
        ans1[i]=change(r,i);
    }
    for(int i=1;i<=n/2;i++)
        ans2[v[i][0]]=i*2;
    printf("!");
    for(int i=1;i<=n/2;i++) printf(" %d",ans2[i]);
    for(int i=1;i<=(n+1)/2;i++) printf(" %d",ans1[i]);
    puts("");
    fflush(stdout);
}

猜你喜欢

转载自blog.csdn.net/roll_keyboard/article/details/81014709
今日推荐