【JZOJ4821】打膈膜

Description

现有 n 个怪物,每个怪物有一个生命值hi,现在你要把它们杀死,你一开始有 m <script type="math/tex" id="MathJax-Element-3">m</script>魔法值,你先手,每回合可以有三种选择,普通攻击,重击(单体生命值减少2),群攻(所有怪物生命值减少1),其中重击,群攻每次使用需要消耗1魔法值,每次攻击后,剩余怪物(生命值严格大于0)每个使你生命值减少1。现在你想知道自己生命值最少能减少多少。

Solution

这题我们显然可以用搜索,动态规划等方法骗分。

但,这题看上去就是贪心。

对于20%数据(没有魔法值),我们考虑从小到大排序,逐个击毙。

扩展到100%的数据,若剩余怪物个数大于2,肯定是先放群攻。

现在来讨论一下剩余怪物个数等于2:那么我们先用重击把怪物打死或生命值减少到1,这时如果较小生命值的怪物生命值为1,我们肯定放群攻。

如果怪物只剩1只了,那么能重击就重击。

在操作过程中如果发现魔法值没有了,就一次次普通攻击即可。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 100001
#define ll long long
using namespace std;
int a[N];
int main()
{
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    int n,m;
    cin>>n>>m;
    fo(i,1,n) scanf("%d",&a[i]);
    sort(a+1,a+n+1);
    int t=n;
    ll ans=0;
    int q=0;
    fo(i,1,n)
    if(a[i]-q>0)
    {
        if(t>2)
        {
            while(m && a[i]-q)
            {
                m--,q++;
                if(a[i]-q) ans+=t;
                else
                {
                    fo(j,i,n)
                    if(a[j]==a[j+1]) t--;
                    else break;
                    t--;
                    ans+=t;
                }
            }
        }
        if(!(a[i]-q)) continue; 
        if(t<=2 && a[i]-q>1 && m)
        {
            while(a[i]-q>1 && m)
            {
                m--;a[i]-=2;
                if(!(a[i]-q)) t--;
                ans+=t;
            }
        }
        if(!(a[i]-q)) continue; 
        if(t==2 && a[i]-q==1 && m)
        {
            m--,q++;
            fo(j,i,n)
            if(a[i]==a[i+1]) t--;
            else break;
            t--;
            ans+=t;
        }
        if(!(a[i]-q)) continue; 
        if(!m || a[i]-q==1)
        {
            ans=ans+(a[i]-q-1)*1ll*t;
            t--;
            ans+=t;
            a[i]=0;
        }
    }
    cout<<ans;
}
posted @ 2016-10-17 18:47  sadstone  阅读(50)  评论(0编辑  收藏  举报