Codeforces Round #679 (Div. 2, based on Technocup 2021 Elimination Round 1) E. Solo mid Oracle

题目:https://codeforces.com/contest/1435/problem/E

每隔d时间造成a伤害,每次造成a伤害后c秒内,每秒都会回复b生命值,生命值回复效果的buff可以叠加。

如果无论对方多少血都是杀死对面,输出-1。否则能击杀对方的生命最大值,生命值比long long大就输出”500000500000“。

思路:

先把  1.直接杀死。2. 只有第一次能直接杀死。3 . 在回血buff叠加过程中,能造成伤害a和之后回血多少来比较。

关键是第三种情况,考虑在T时刻,回血次数t只与前面min(T,c)的时间长度内造成多少次a伤害有关。

如果写成一个大暴力就是如下 

    long long ans=0,tmp=ans,T=0;
    while(T++)
    {
        if(T<c) heal=(ll)ceil(T*1.0/d)*b;//这一刻回了多少血
        else heal=(ll)ceil(c*1.0/d)*b;
        tmp-=heal;
        if(T%d==0)//取到生命最大值都是在造成a伤害后计算是最优的
        {
            tmp+=a;
            if(tmp<=ans) break;
            else ans=tmp;
        }
    }

 

由于T时刻回血量heal是向上取整,以前T∈(0,d)回血b,T∈[d,2*d)回血2*b。。。。。。所以可以用一个等差数列求和直接计算。

在我们分类之后,可以发现在这种需要计算的情况只有当a>=b*c&&c>=d。

所以我们只要计算出T∈(0,c)的情况,也就是前面是一个等差数列,c秒后每秒内回血都是一个固定值ceil(c*1.0/d)*b。c秒后直接讨论a与每轮回血值就好了。

那么在c秒前,怎么找到tmp<=ans的情况呢,ts设为T=ts*d的时候达到最优,tmp<=ans就是在a<=ts*b*d的时候。

加上c秒前的限制就是ts=min(c/d,a/(b*d))+1。

#include<bits/stdc++.h>
#include<ext/rope>
//#include<hash_map>
#define sd(x) scanf("%d",&x)
#define lsd(x) scanf("%lld",&x)
#define ms(x,y) memset(x,y,sizeof x)
#define fu(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define all(a) a.begin(),a.end()
using namespace std;
using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int maxn=1e5+91;
const int mod=1e9+7;
const int INF=1e9+7;
const double pi=acos(-1);
int ans[maxn],mx[maxn];
int main() 
{int n;sd(n);
    while(n--)
    {
        ll a,b,c,d;
        lsd(a);lsd(b);lsd(c);lsd(d);
        ll ans=a;
        if(a>b*c) printf("-1\n");
        else
        {
            if(b*d>=a||c<d) printf("%lld\n",ans);
            else
            {
                ll ts=min(c/d,a/(b*d))+1;
                ans=ts*a-(ts-1)*(ts)/2*b*d;
                if(a<=ts*b*d) 
                {
                    printf("%lld\n",ans);
                    continue;
                }
                ll heal=(ll)ceil(c*1.0/d)*b;//每次回复的生命值
                //c>=d
                //到第一个d
                if(a>=(d-c%d)*heal) 
                {
                    printf("%lld\n",ans);
                }
                else
                {
                    ans+=a-(d-c%d)*heal;
                    if(a<=d*heal) printf("%lld\n",ans);//后面扣血和加血平衡了
                    else printf("500000500000\n");
                }
                
            }
        }
    }
    return 0;
}

 

Codeforces Round #679 (Div. 2, based on Technocup 2021 Elimination Round 1) E. Solo mid Oracle

上一篇:JDBC


下一篇:SQLService表连接的几种方式