题目翻译

在某款电脑游戏里,角色初始生命 $hc$,初始攻击 $dc$。怪物初始生命 $hm$,初始攻击 $dm$。

而你有 $k$ 次机会,将攻击力永久提升 $w$ 或者将生命永久提升 $a$ 。

每一轮,角色攻击怪物,怪物掉 $dc$ 生命。怪物攻击角色,角色掉 $dm$ 生命。

问若干轮以后,角色能否击杀怪物并且角色存活。

击杀怪物定义为:怪物生命 $\ngtr 0$。

角色存活定义为:角色生命 $>0$。

题目思路(不完整)

我们枚举这 $k$ 次机会,分别是加攻击还是加生命。然后判断角色增加这些属性后,能否击败怪物。

而且每一轮的攻击,如果角色击败了怪物,怪物不会攻击角色。也就是说,怪物可以少打一轮伤害。

题目代码(不完整)

void solve()
{
    long long hc,dc,hm,dm,k,w,a;
    cin>>hc>>dc>>hm>>dm>>k>>w>>a;//输入属性
    for(long long i=0;i<=k;i++)
    {
        long long x=i,y=k-i;//枚举加攻击或加生命
        long long rnd=ceil(hm*1.0/(dc+x*w));//用怪物血量除以角色攻击得到轮数
        if(dm*(rnd-1)<hc+a*y)//如果怪物打出的伤害比角色生命少
        {
            puts("YES");//可以通关
            return;
        }
    }
    puts("NO");
}

但是,看似没问题,实则会在第 $13$ 个数据点错误。

让我们导出看一下。

Input
1
1 1
1000000000000000 1000000000
200000 1 10000000000

Output
YES

Answer
NO

我们进行调试,分别输出每个循环的结果。

1
1 1
1000000000000000 1000000000
200000 1 10000000000
加攻击机会数:0 加生命机会数:200000 总轮数:1000000000000000 怪物打出伤害:2003764204206896640 角色生命:2000000000000001
加攻击机会数:1 加生命机会数:199999 总轮数:500000000000000 怪物打出伤害:1001882101603448320 角色生命:1999990000000001
加攻击机会数:2 加生命机会数:199998 总轮数:333333333333334 怪物打出伤害:667921401402298880 角色生命:1999980000000001
加攻击机会数:3 加生命机会数:199997 总轮数:250000000000000 怪物打出伤害:-8722430986553051648 角色生命:1999970000000001
YES

答案竟然爆 long long 了。

那么我们没办法了吗?错!__int128 了解一下?

我们给总轮数换上 __int128 即可。

总结

思想是对于加攻击还是加生命都考虑一下,找出每种可能。

注意数据范围。

代码不给了,就是改个 __int128 的事。

最后修改:2023 年 04 月 22 日
v我50吃疯狂星期四