这场总体难度不算大(感觉C,D,E的难度居然出奇的一致)

如果码力再强点,也许是能AK的,可惜只切了四题。不过一下子rk涨了100多,还是有点出乎我的意料hh


题目大意(E. Solo mid Oracle)

假设一个单位有H点生命值,你拥有一个技能能修改该单位的生命值H。

若在某一时刻t发动该技能,效果如下:首先,在t时刻对该单位在造成a点伤害;然后在t+1,t+2,t+3,...,t+ct+1,t+2,t+3,...,t+c时刻治疗该单位,每次均治疗b点生命值

技能的冷却时间为d,也就是说,若在时刻t发动技能,则在t+d时刻才能继续使用该技能

0时刻单位的初始生命值为H,H>0。若某一时刻该单位生命值0\leq 0,则该单位被击杀

若要使该单位被击杀,H的最大值为多少?若无解则输出-1。

数据范围

共有T组数据(1t50)(1\le t\le 50),输入为a,b,c,da,b,c,d,其中1a,b,c,d1061\le a,b,c,d\le 10^6

要求输出一个整数,即满足条件H的最大值。

题解

拿到这种题,首先应分析一下隐藏的性质:

  1. a>b×ca>b \times c,则H无最大值,答案必为-1。故接下来只需讨论ab×ca\le b \times c的情况
  2. 应该在冷却时间结束之后马上继续释放技能
  3. tct\le c后,那么前面释放过的已经作用完的技能其实是为该单位增加了bcab*c-a点的生命值,故只需要考虑t<ct<c的情况
  4. 该单位的生命值最低的时刻应该是刚好造成伤害的时刻,即0,d,2d,...,kd0,d,2d,...,kd

于是乎,对于每一个在t=0,d,2d,...,kdt=0,d,2d,...,kd中且满足t<ct<c的时刻,找出最优时刻计算答案即可

同时,由于H是关于t的凸函数,故可以用三分来找答案

O(1)做法

先推式子,然后求导得到生命值最低的时刻再计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,c,d;
int main(){
int T;scanf("%d",&T);
while(T--){
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
if(a>b*c)printf("-1\n");
else {
ll k=a/(b*d),ans=0;
ans=max(ans,(k+1)*a-(1+k)*k/2*b*d);
k++;
ans=max(ans,(k+1)*a-(1+k)*k/2*b*d);
printf("%lld\n",ans);
}
}
return 0;
}

三分

说实话都能求导找k的最优解了,还用三分就挺zz的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a,b,c,d,ans;
ll get_num(ll k){
return (k+1)*a-(1+k)*k/2*b*d;
}
void solve(ll l,ll r){
while(l<r-1){
ll lm=l+(r-l)/3,rm=r-(r-l)/3;
if(get_num(lm)>=get_num(rm)){
ans=max(get_num(rm),ans);
r=rm-1;
}
else {
ans=max(get_num(lm),ans);
l=lm+1;
}
}
ans=max(ans,max(get_num(l),get_num(r)));
}
int main(){
int T;scanf("%d",&T);
while(T--){
scanf("%lld%lld%lld%lld",&a,&b,&c,&d);
if(a>b*c)printf("-1\n");
else {
ans=0;
ll k=c/d;
solve(0,k);
printf("%lld\n",ans);
}
}
return 0;
}