题解 | #打怪#

打怪(hard)

https://ac.nowcoder.com/acm/contest/59248/C

打怪

当游戏结束时必须满足以下两个条件之一:

  • 攻击力等于对方的血量
  • 防御力等于对方的攻击力

当攻击力为a时,防御力为b时。获得一个金币的代价为HP1a(ADb)\lfloor\frac{HP-1}{a}\rfloor*(AD-b)

对于任何一种情况来说都可以归纳成以下表格情况情况: (wi=HP1i,iHPw_i=\lfloor\frac{HP-1}{i}\rfloor, i可以比HP大)

扣血量 敌方攻击次数
ADAD w1,w2,w3,...,wiw_1, w_2, w_3,...,w_i
AD1AD-1 wi,wi+1,wi+2,...,wjw_i, w_{i+1}, w_{i+2},...,w_j
... ...
11 wk,wk+1,wk+2,...w_k, w_{k+1}, w_{k+2},...

我们可以观察到升级防御时后,将会出现两次wiw_i。 之后将相同攻击次数的情况划分成同一类后获得n\sqrt{n}不同的数,对于某个攻击次数为yy、个数为lenlen的情况,贪心考虑后得到两种代价,每次选择代价小的那个,然后累计到ans上。

  • 为扣血量x的最后一个:(xy)+((x1)ylen)(x * y)+((x-1)*y*len)
  • 不是最后一个:xlenyx*len*y

当攻击力等于对方的血量时,y=0y=0 防御力等于对方的攻击力,x=0x=0

对于中间的任何情况来说,结束的代价为ans+(1+x)x/2yans+(1+x)*x/2*y。 当x=0x=0时退出循环即可:

void slove() {
    ll ad = read(), hp = read();
    hp--;
    ll res = hp * (1 + ad) * ad / 2, ans = 0;
    ll x = ad;
    for (ll l = 1, r, y; l <= hp && x > 0; l = r + 1) {
        y = hp / l, r = hp / y;
        ll len = r - l + 1;
        // 总代价
        res = min(res, y * x * (1 + x) / 2 + ans);

        if (x - len <= 0) {
            ans += (2 * x - 1) * len * y;
            x--;
        } else ans += x * len * y;
    }
    print(min(res, ans));
}
全部评论

相关推荐

04-03 22:39
重庆大学 Java
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务