dtoj#4179. 排行(rank)

题目描述:

传说在2345年,Byteland中举行了一场质因数分解比赛,规则中说名次为1,2,3的参赛者将获得奖金。比赛顺利结束了,但是选手们发现主办方进行了暗箱操作,他们将选手从一个整数a<1开始排名,所以选手的名次为a,a+1,a+2...0,1,2,3 ...,也就是说拿到奖金的并不是真正的前三名。虽然选手怨声载道,主办方坚称比赛公平公正。

今年是3345年,你打算还原千年前这场比赛的名次,但是主办方称由于技术原因排名遗失了,连用于排名的a也丢失了。所幸,在Byteland中生活的都是机器人,所以你可以询问这些千年前的参赛选手。为了谨慎起见,你可以每次询问一个参赛者,某一个参赛者的比赛成绩比它好还是比它差。但是,机械心理学家告诉你,这些选手不一定愿意回答你的提问。

具体地:

名次小于1的选手由于耿耿于怀,如果它应该回答另一个参赛者成绩比它好,它就会选择不回答,否则它会如实回答。

名次为1的选手决定闷声大发财,它无论如何都不会回答任何提问。

名次为2的选手只当询问排名为3的选手时才回答比排名3的好,其他时候都不回答。

名次为3的选手趾高气扬,如果它应该回答另一个参赛者成绩比它好,它就会选择不回答,否则它会如实回答。

名次大于3的选手感觉自己水平不行,如果它应该回答另一个参赛者成绩比它差,它就会选择不回答,否则它会如实回答。

1<=n<=1000,你需要在11500次询问内还原每个选手的名次。

思路:

总结对于x<1的会对于比他大的如实回答,x>3的会对比他小的如实回答,还有2问3有回答,其余都是不回答。于是我们可以先用2*n次询问找出最小的数以及x>3的数。

我们把不是x>3的数进行二分排序,最后三个数就是123,接下来在两两枚举这三个数,确认每个数分别对应哪个名次。

在同理把x>3的也二分排序一下。

询问次数是2*n+nlogn+6。时间效率是n2

以下代码:

#include "rank.hpp"
#define il inline
using namespace std;
const int N=1005;
vector<int> ans;
bool f[N];
int h[N],a[N],tot,b[N];
il int Min(int x,int y){
    char c1=ask(x,y),c2=ask(y,x);
    if(c1=='g')f[x]=1;if(c2=='g')f[y]=1;
    if(c1=='b'||c2=='g')return x;
    return y;
}
il void ins1(int x){
    int l=1,r=tot;
    while(l<r){
        int mid=(l+r+1)>>1;
        if(ask(a[mid],x)=='b')l=mid;
        else r=mid-1;
    }
    for(int i=tot;i>=l+1;i--)a[i+1]=a[i];
    a[l+1]=x;tot++;
}
il void ins2(int x){
    int l=1,r=tot;
    while(l<r){
        int mid=(l+r+1)>>1;
        if(ask(x,a[mid])=='g')l=mid;
        else r=mid-1;
    }
    for(int i=tot;i>=l+1;i--)a[i+1]=a[i];
    a[l+1]=x;tot++;
}
vector<int> work(int n){
    int x=0;
    for(int i=1;i<n;i++)x=Min(x,i);
    a[1]=x;tot=1;
    for(int i=0;i<n;i++){
        if(i==x||f[i])continue;
        ins1(i);
    }
    bool pd=0;
    for(int i=tot-2;i<=tot;i++){
        for(int j=tot-2;j<=tot;j++){
            if(i!=j&&ask(a[i],a[j])=='b'){
                b[a[i]]=2;b[a[j]]=3;x=a[j];
                pd=1;break;
            }
        }
        if(pd)break;
    }
    for(int i=tot-2;i<=tot;i++)if(!b[a[i]])b[a[i]]=1;
    for(int i=1;i<tot-2;i++)b[a[i]]=i-tot+3;
    tot=1;a[1]=x;
    for(int i=0;i<n;i++){
        if(f[i])ins2(i);
    }
    for(int i=2;i<=tot;i++){
        b[a[i]]=i+2;
    }
    for(int i=0;i<n;i++)ans.push_back(b[i]);
    return ans;
}
View Code

 

posted @ 2019-02-21 23:41  Jessiejzy  阅读(190)  评论(0编辑  收藏  举报