Loading

2022牛客寒假算法基础集训营2 A. 小沙的炉石(思维)

A. 小沙的炉石

链接:https://ac.nowcoder.com/acm/contest/23477/A
来源:牛客网

题目描述

小沙热衷于玩决斗法,今天他和他的弟弟玩起了炉石,弟弟特别特别的菜,但是为了照顾弟弟的自尊心,所以小沙想要恰好将弟弟斩杀。

恰好斩杀:弟弟的血量恰好变成0。

小沙当前的手上有nn张法术进攻牌,每张牌都会消耗一点法力,造成一点基础伤害,有mm张法术回复牌,不需要消耗法力值,每次可以恢复一点法力。小沙一开始有一点法力,法力没有上限。

他们都属于法术。

小沙场上有一个随从。他可以使你施法法术后使你的法术伤害+1。

每张法术进攻牌的伤害都等于法术伤害+基础伤害组成。

法术伤害初始为0。

你无法对该随从使用进攻法术牌。

随从也无法攻击。

img

现在小沙想问你,小沙现在能否恰好将弟弟斩杀。

输入描述:

第一行输入两个数1≤n≤109,0≤m≤1091≤n≤109,0≤m≤109分别代表小沙手上的法术进攻牌和法术回复牌。
第二行输入一个1≤k≤1051≤k≤105代表小沙有kk次询问
随后kk行每行输入一个整数1≤x≤10181≤x≤1018代表弟弟的血量

输出描述:

对于小沙的每一次询问,返回一行字符串
如果可以将弟弟斩杀输出“YES”(不带引号)
否则输出“NO”(不带引号)

示例1

输入

复制

2 1
3
1
4
6

输出

复制

YES
YES
NO

挺巧妙的思维题,比赛的时候理解错题意了,浪费半小时写了错的二分...

首先可以发现,我们能够控制出牌的顺序从而能够调节造成的伤害。如果想要造成的伤害最大,那么需要先出掉m张回复牌再出掉min(n, m + 1)张进攻牌(攻击次数由n和m共同约束);如果想要造成的伤害最小,那么需要进攻一次回复一次,再进攻再回复(注意回复的时候也会涨攻击,因此每次造成的攻击是公差为2的等差数列)...

不妨设\(a = min(n, m + 1)\),由等差数列求和公式,可得进攻a次情况下的攻击范围:\([\frac{(1+(2\times a-1))\times a}{2},a+\frac{(m+m+a-1)\times a}{2}]\)。可以证明限定攻击次数为a后绝大部分情况下这一段区间的任何伤害值都可以达到。

上面是固定攻击次数为min(n, m + 1)的情况,实际上为了达到完美击杀,并不一定要用光手里的攻击卡。根据给定的x,结合上面的公式,可以确定出想要达成完美击杀进行的攻击次数的候选值。因为上述攻击范围区间左端点化简后为\(a^2\),令\(a^2=x\)\(a=\lfloor sqrt(x)\rfloor\),此即需要的攻击次数。可以验证,如果攻击a+1次,那么最终伤害区间左端点一定大于x,必然不可能造成完美击杀。这时还需要验证区间右端点是否大于等于x,直接把上面求出来的候选值\(a=\lfloor sqrt(x)\rfloor\)带入右端点表达式\(a+\frac{(m+m+a-1)\times a}{2}\),判断其是否大于等于x即可。

#include <iostream>
#include <map>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#define int long long
#define ll long long
#define pb push_back
#define pii pair<int,int>
using namespace std;
ll n, m, k, x;
signed main() {
	cin >> n >> m;
	cin >> k;
	for(int i = 1; i <= k; i++) {
		ll x;
		cin >> x;
		ll atknum = min(n, m + 1);
		ll s = (ll) sqrt(x);
		atknum = min(atknum, s);
		if(atknum + (m + m + atknum - 1) * atknum / 2 >= x) puts("YES");
		else puts("NO");
	}
	return 0;
}
posted @ 2022-01-26 23:56  脂环  阅读(82)  评论(0编辑  收藏  举报