牛客小月赛46 E 对决

题意就不说了,这题不出意外的话,就是看能不能找出一个一般人想不到的情况

首先就是排序后二分,找出第一个能赢的下标,那么后面的都是1,前面的都是0,这里需要结构体存储开始的下标

核心就是判断中间的一个人能不能取得最终胜利?

思路:

前1 ~ m-1个一定是和最小的m-1个人比赛,而且不能是自己,这时可以用*2就不要用/2,到最后一个的时候就两个法宝有剩余的就都用上。

一般人想不到的情况就是数据

3 1

1 3 6

1是可以赢的,*2不一定用到1身上(相信比较容易想到,但除了这个情况确实没必要)

让3*2可以赢了6,最后就是1和3比,因为3/2==1,最后1赢得比赛。

注意:这种情况只有最后判断就行,因为需要两个法宝,前面小的就用2个,最后的比赛不可能赢的

所以最后map标记有(最大值 / 2)这个数的话,而且选择的数 >= 最大值 / 2 / 2直接返回YES就行。

5 1

1 2 4 5 6

这个数据的1就是不能赢的

if(f[0]==0&&f[1]==0&&mp[x[n].first/2]&&now>=x[n].first/2/2) return 1;

总代码:

不用pair的结构体:Ubuntu Pastebin

#include<bits/stdc++.h>
using namespace std;
#define fo(a,b) for(long long i=a;i<=b;i++)
#define ll long long
#define M 1000005
int n,m;
pair<int,int>x[M];
map<int,int>mp;
int ans[M];
int check(int now,int d){
    if(d==n) return 1;
    int f[2]={0};           //f[0]表示*2法宝,f[1]表示/2法宝,要知道/2比*2好用
    int mm=m;
    fo(1,mm){
        if(i==d){mm++;continue;}
        if(i==mm){               //最后一个
            if(f[0]==0&&f[1]==0&&mp[x[n].first/2]&&now>=x[n].first/2/2) return 1;     //特殊判断,其实有缺陷,但数据应该卡的不是很死可以过

            return (f[0]?now:now*2)>=(f[1]?x[n].first:x[n].first/2);
        }
        else if(x[i].first>now){        //有异常的先用*2
            if(now*2>=x[i].first&&f[0]==0) f[0]=1;
            else if(now>=x[i].first/2&&f[1]==0) f[1]=1;
            else return 0;
        }
    }
    return 1;
}
int main(){
    cin>>n>>m;
    fo(1,n){
        cin>>x[i].first;
        mp[x[i].first]=1;
        x[i].second=i;
    }
    sort(x+1,x+n+1);
    int l=1,r=n,an=0;          //二分
    while(l<=r){
        int mid=(l+r)/2;
        if(check(x[mid].first,mid)){
            r=mid-1;
            an=mid;
        }
        else l=mid+1;
    }
    fo(1,n) ans[x[i].second]=(i>=an);       //下标存储
    fo(1,n) cout<<ans[i]<<" ";
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_58177653/article/details/123748332