题目链接:点击这里
题目大意:
初始时,你有
1
1
1 点体力;有
n
n
n 张攻击牌,每张攻击牌可以消耗
1
1
1 点体力并造成
1
1
1 点基础伤害;有
m
m
m 张法术牌,每张牌恢复
1
1
1 点体力(体力 无上限);每次使用一张牌后会使之后的攻击牌增加
1
1
1 点伤害,求是否可以使用这些牌恰好造成
k
k
k 点伤害
题目分析:
我们不妨设
n
≤
m
+
1
n\le m+1
n≤m+1 (若
n
>
m
+
1
n>m+1
n>m+1 时可以看作
n
=
m
+
1
n=m+1
n=m+1 ,因为多余的攻击牌会因缺少体力而无法使用)
我们发现如果采取
攻
击
牌
,
法
术
牌
,
攻
击
牌
,
法
术
牌
.
.
.
.
.
.
攻击牌,法术牌,攻击牌,法术牌......
攻击牌,法术牌,攻击牌,法术牌...... 这样的出牌顺序会使造成的伤害最小,造成的伤害为
∑
i
=
1
n
2
i
−
1
=
n
2
\sum_{i=1}^n2i-1=n^2
∑i=1n2i−1=n2
如果采用
法
术
牌
,
法
术
牌
.
.
.
.
.
.
,
攻
击
牌
,
攻
击
牌
.
.
.
.
.
.
法术牌,法术牌......,攻击牌,攻击牌......
法术牌,法术牌......,攻击牌,攻击牌...... 这样的出牌顺序会使造成的伤害最大,造成的伤害为
∑
i
=
1
n
(
m
+
i
)
=
m
n
+
n
(
n
+
1
)
2
=
n
(
2
m
+
n
+
1
)
2
\sum_{i=1}^n(m+i)=mn+\frac{n(n+1)}{2}=\frac{n(2m+n+1)}{2}
∑i=1n(m+i)=mn+2n(n+1)=2n(2m+n+1)
我们可以通过法术牌和攻击牌的使用顺序使得伤害值可以取到上下界中的所有值,因此我们可以先算出造成
k
k
k 点伤害至少需要的牌数
x
=
k
x=\sqrt k
x=k ,然后跟
n
n
n 取一下最小值,然后再看
x
x
x 能造成的最大伤害是否大于
k
k
k 即可
具体细节见代码:
//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<unordered_map>
#define ll long long
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
#define int ll
#define endl '\n'
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
using namespace std;
int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 1e6+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
int n,m,k;
signed main()
{
n = read(),m = read();
n = min(n,m+1);
int t = read();
while(t--)
{
k = read();
int x = sqrt(k);
x = min(x,n);
if(x*(2*m+x+1)/2 >= k) puts("YES");
else puts("NO");
}
return 0;
}