题意
链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
小沙热衷于玩决斗法,今天他和他的弟弟玩起了炉石,弟弟特别特别的菜,但是为了照顾弟弟的自尊心,所以小沙想要恰好将弟弟斩杀。
恰好斩杀:弟弟的血量恰好变成0。
小沙当前的手上有nnn张法术进攻牌,每张牌都会消耗一点法力,造成一点基础伤害,有mmm张法术回复牌,不需要消耗法力值,每次可以恢复一点法力。小沙一开始有一点法力,法力没有上限。
他们都属于法术。
小沙场上有一个随从。他可以使你施法法术后使你的法术伤害+1。
每张法术进攻牌的伤害都等于法术伤害+基础伤害组成。
法术伤害初始为0。
你无法对该随从使用进攻法术牌。
随从也无法攻击。
现在小沙想问你,小沙现在能否恰好将弟弟斩杀。
输入描述:
第一行输入两个数1≤n≤10^9,0≤m≤10^9,分别代表小沙手上的法术进攻牌和法术回复牌。
第二行输入一个k,1≤k≤10^5,代表小沙有k次询问
随后kkk行每行输入一个整数x,1≤x≤10^18代表弟弟的血量
输出描述:
对于小沙的每一次询问,返回一行字符串
如果可以将弟弟斩杀输出“YES”(不带引号)
否则输出“NO”(不带引号)
示例1
输入
复制2 1 3 1 4 6
2 1 3 1 4 6
输出
复制YES YES NO
YES YES NO
说明
如果弟弟的血量为1
小沙可以直接使用一张法术进攻牌伤害为1。恰好斩杀
如果弟弟的血量为4
小沙可以直接使用一张法术进攻牌伤害为1,随后使用一张法术回复牌,然后使用一张法术进攻牌,总计造成1+0+3点伤害。恰好斩杀
如果弟弟的血量为6
则无法斩杀
思路
对于这道题,我们应先考虑最多能使用几张进攻牌u=min(m+1,n),对于最多u张进攻牌的情况,我们把m张牌都放在最前面的情况能攻击的血量最多;而我们枚举使用1,2,3.......u张进攻牌时,就会有u个区间,每个区间的数都是连续的,因为只要使用这x(1<=x<=u)张进攻牌时,只要交换相邻两张就可以将数字加一或减一。
因而使用这x张牌的最小值的情况就是1 0 1 0 1.....(1代表使用进攻牌,0代表使用回复牌),所以情况应为 1 3 5 7....,由等差数列可知和为x*x。
对于最大值的情况,一定是把m张回复牌放前面,情况为 m+1,m+2,.......m+x。由等差数列可知这个最大值为 x*(m+1+m+x)/2;
所以区间段每个区间段应为[x*x,x*(m+1+m+x)/2],共有n个区间段;
所以我们可以枚举每一个区间段,用二分的方式找到弟弟的血量是否在区间段中。
接下来我们讲这道题的一个巧妙的做法:
对于相邻两个区间段比如[1 4] [5 10],这两个区间段包含所有数,所以两个区间段可以合并,
对于[1 5] [5 10]也可以合并,但对于[1 3] [5 10],中间有一个4不在区间当中;所以当我们满足前一个区间的右端点的值小于等于后一个区间的左端点的值减一时这两个区间就可以合并;
所以设使用a张攻击牌(1<=a<=m-1) (m-1为回复牌)应该满足:
a*(m+1+m+a)/2 >= (a+1)*(a+1) -1 则不可以将两个区间合并;
所以 化简得 am + a*(a+1)/2 >=(a+1)*(a+1)-1;
am+a*(a+1)/2>= a*a+a*(a+1)/2>=(a+1)(a+1)-1;
解得 a>=3;
因此我们证明只要当a>=3时,所有的区间都满足区间合并的条件;
所有我们只要特判 a=1和a=2的情况;
我们可以先枚举出区间
[1, m+1] ; [4 ,2m+3]; [9 ,3m+6].........[ ,max]; 当攻击次数大于等于3时即连续;
-------------------------------即这一段连续
当m=1时 当n>=1时有两个区间[1,2] [4, 7(max)]需要特判3;
当n==1时有一个区间[1,2(max)],不需要特判;
当m=2时 当n==1时有一个区间[1,3(max)],不需要特判;
当n==2时有两个区间 [1,3] [4,7(max)],不需要特判;
当n>=3时有三个区间区间[1,3] [4,7] [9,11] ,需要特判8;
当m>=3时 当n==1时有一个区间 [1,4(max)]不需要特判;
当n==2时有两个区间[1,4] [4 ,9(max)]不需要特判;
当n>=3时区间有 [1, m+1] ; [4 ,2m+3]; [9 ,3m+6].........[ ,max]
-------------------------------这一段连续
又m+1>=4-1;2m+3>=9-1所有全部连续
因此只有两个特判,最后只需要判断x<=max是否成立即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll n,m,k,x;
cin>>n>>m;
ll u=min(m+1,n);
x=u+m;
ll ans=u*(m+1+x)/2;
cin>>k;
while(k--){
ll x;
cin>>x;
if(m==1&&x==3){
cout<<"NO"<<endl;
continue;
}
if(m==2&&x==8){
cout<<"NO"<<endl;
continue;
}
if(x<=ans)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}