JZOJ 4821 【NOIP2016提高A组模拟10.15】打膈膜

打膈膜

n 个怪物,第i个怪物有 hi 滴血, DDX m 点魔法值,然后DDX和怪物们依次行动,每一回合, DDX 先行动,然后怪物们再行动。
DDX每次可以选择以下行动之一:
这里写图片描述
每次行动完后每个存活的怪物都会给 DDX 造成一点伤害,假设 DDX 可以承受足够的伤害,求 DDX 受到伤害的最小值。

数据范围

n 105 m 100 hi 105

题解

这题看上去很难,事实上可以用一种十分玄学的方法做——迷之贪心。
首先,按 hi 从小到大排序。
每次行动若还剩下大于两个的怪物,则用群体攻击,如果只有小于等于两个怪物了,则看此次被攻击的怪物的血量是否为 1 ,若为1,则用普通攻击把它打死,否则重击它。
直到用到没魔法值了,就一下一下的普通攻击打完怪物即可。

Code(Pascal)

label 123,234;
var
    ans,o,oo:int64;
    n,m,k,l,i:longint;
    h:array[0..120000] of int64;
function min(a,b:int64):int64;
    begin
        if a>b then exit(A)
        ELSE EXIT(B);
    end;
procedure qsort(l,r:longint);
    var
        i,j:longint;
        m:int64;
    begin
        i:=l;
        j:=r;
        m:=h[(l+r) div 2];
        repeat
            while h[i]<m do inc(i);
            while h[j]>m do dec(j);
            if i<=j then
            begin
                h[0]:=h[i];
                h[i]:=h[j];
                h[j]:=h[0];
                inc(i);
                dec(j);
            end;
        until i>j;
        if l<j then qsort(l,j);
        if i<r then qsort(i,r);
    end;
begin
    assign(input,'game.in'); reset(input);
    assign(output,'game.out'); rewrite(output);
    readln(n,m);
    for i:=1 to n do
    read(h[i]);
    qsort(1,n);
    l:=1;
    for i:=1 to m do
    begin
        if l<n-1 then
        begin
            inc(o);
            while h[l]<=o do
            begin
                inc(l);
                h[l-1]:=0;
            end;
            ans:=ans+(n-l+1);
            oo:=o;
        end
        else
        begin
            h[n-1]:=h[n-1]-o;
            h[n]:=h[n]-o;
            O:=0;
            234:
            if h[l]=1 then
            begin
                h[l]:=0;
                inc(l);
                if l>n then goto 123;
                ans:=ans+(n-l+1);
                goto 234;
            end
            else
            begin
                dec(h[l],2);
                if h[l]=0 then inc(l);
                if l>n then goto 123;
                ans:=ans+(n-l+1);
            end;
        end;
    end;
    if l>=n-1 then oo:=0;
    if l<=n then
    for i:=l to n do
    ans:=ans+min(0,h[i]-oO)*(n-i+1)-1;
    123:
    writeln(ans);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值