题意就不说了,这题不出意外的话,就是看能不能找出一个一般人想不到的情况
首先就是排序后二分,找出第一个能赢的下标,那么后面的都是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;
}