标签:思维,二分
思路
首先我们要知道最多能打出的进攻牌为n和m+1(体力限制)两者的较小值,其次如果固定进攻牌的数量,将进攻牌尽量先打出时伤害最小,这时的出牌顺序应该是进攻,回复,进攻,回复…,这样打出的的伤害sum=1+3+5+…+n(这个n是指固定的进攻牌的数量)=n^2,而将进攻牌尽量后打出且将回复牌尽量全打出时伤害最大,这时的出牌顺序应该是回复,回复…进攻,进攻…,这样打出的伤害sum=m+1+m+2+…+m+n=nm+n(n-1)/2,知道伤害的上下限之后我们还需要证明的点是是否能将伤害区间内所有的值都取到,这个其实比较好想,从最小伤害的出牌顺序开始,只要将任意进攻牌和它之后的回复牌交换,就能使伤害+1,所以是可以取完的
二分的具体写法就是二分进攻次数,每次计算伤害的上下限,只要血量在此范围内就可以恰好击杀,反之不能
代码实现
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
long long n,m,x;
int k;
int main(){
cin>>n>>m;
cin>>k;
n=min(n,m+1);
while(k--){
cin>>x;
int book=0;
long long l=1,r=n;
while(l<=r){
long long mid=(l+r)/2;
long long xia=mid*mid;
long long shang=mid*m+mid*(mid+1)/2;
if(x>=xia&&x<=shang){
book=1;
break;
}else if(x<xia) r=mid-1;
else l=mid+1;
}
if(book) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}