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

22 篇文章 0 订阅
5 篇文章 0 订阅

题目

这里写图片描述

样例输入:
这里写图片描述
3 4
2 4 4

样例输出:
这里写图片描述
6

数据范围:
这里写图片描述


剖解题目

。。。。。。


思路

第一眼就是觉得,肯定是dp题,然而发现好难搞,然后就贪心的想了想(其实是打了太多游戏所得到的经验),明显觉得群伤更优于重击(多人时),然而不会证,就没有打。


解法

首先很明显一定是先放技能更好。(^o^)/~。
50%:首先怪物生命从小到大排个序,我们一定得先在前面把技能放了。直接枚举放哪个技能就好了。这里一个小剪枝优化:就是当前怪物剩下1点血后,就必然放群攻。
对于技能,不需要暴力修改。
对于群攻,用一个数组记录释放过次数。
对于重击,只要少加一回合答案即可。
时间 O(nlogn+2m) .

80%:dp。
设 f[i][c][z][q] 表示现在有 i 点魔法值,正在打第 c 个怪(前 c−1 个 都打完了),对这个怪用了 z 次重击,一共用过 q 次群攻,从现在到结束最少要多少生命。 可以得到 f[i][n + 1][z][q] = 0,答案是 f[m][1][0][0]。 当前怪的生命值是 hi −2z−q,如果选择重击,那么从 f[i−1][c][z + 1][q] 转移,如果选择群攻,从 f[i−1][c][z][q + 1] 转移。 时间复杂度 O(nlogn + nm2),空间可以用滚动数组优化到 O(nm)。

100%(1):注意到一些优化:一是快速找到当前怪物被打死后,下一个怪是谁;二是魔法值用完后要能 快速算答案。 这个时候总状态数不会很多(2z + q 6 hi,i + z + q 6 m…),上界是 O(m^4),实际上几乎是 O(m^3) 的。 写哈希或用 std::map 进行记忆化搜索,时间复杂度 O(nlogn + m^3 logm)

100%(2):打过游戏,知道群攻更赚。
当在场上怪物的人数超过2个时,就用群攻。等于2时随意。等于1时用重击。
这明显正确


代码

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define ll long long

using namespace std;

const int maxn=1e5+5;
int a[maxn],n,m,num;
ll ans,now;

int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    scanf("%d%d",&n,&m);
    fo(i,1,n) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    int i=1; now=n; 
    while (m){
        if (a[i]-num==1||now>2) ++num;
        else if (a[i]-num>1||now<=2) a[i]-=2;
        --m;
        while (a[i]-num==0) ++i,now--;
        ans+=now;
    }
    ans=ans-now;
    fo(h,i,n) ans=ans+(ll)(n-h+1)*(ll)(a[h]-num);
    printf("%lld",ans);
}

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值