Codeforces Round #339 (Div. 2) D.Skills(贪心)

 转载自:http://dirtytao.com/codeforces-round-339-div-2/

题意:

一共n个技能,最大等级都为A,当前等级已给出。现在有m个技能点,需要通过这些技能点使“战斗力”最大化战斗力=满级技能数Cf + 最低技能等级Cm,输出最大化的战斗力和对应的技能等级。

思路:

先将所有技能等级和位置都记录下来,按照等级从小到达进行排序,然后求出前缀和sum[i]。接下来我们能做两种操作:①.把当前技能等级高的提升为为满级。②把 当前技能等级最低的技能提升到一定等级。我们可以枚举满级的技能数i的所有情况,使用技能点为A*i-(sum[n]-sum[i]),记为p_cost。剩下技能点为m-p_cost,记为left_cost。我们用剩下来的left_cost来填充最低技能点:找到技能left_cost所能填充的最高高度就可以了(有种把水倒进阶梯等增的的水池的感觉),如图所示,A区为填充最高技能所需要的技能点,B区为填充最低技能所需要的技能点,A+B=m,最低技能等级为min(A,(sum[j]+left_cost)/j),j表示B区覆盖的技能数。于是我们只要枚举下所有情况,维护一个最大战斗力的值就可以了。

IMG_2045

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define ll __int64     
#define lson l,m,rt*2
#define rson m+1,r,rt*2+1
const int maxn = 1000001;
const int INF=1<<30;
const double EPS = 1e-5;
const double PI = acos(-1.0);
struct node
{
    int x;
    int id;
}a[100005];
ll sum[100005];
bool cmp1(node a,node b)
{
    return a.x<b.x;
}
bool cmp2(node a,node b)
{
    return a.id<b.id;
}
int main()
{
    int t,n,i,j,cf,cm;

    ll A,m;
    while(scanf("%d%I64d%d%d%I64d",&n,&A,&cf,&cm,&m)!=EOF)
    {
        for(i=0;i<n;++i)
        {
            scanf("%d",&a[i].x);
            a[i].id=i;
        }
        sort(a,a+n,cmp1);
        sum[0]=0;
        for(i=1;i<=n;++i)
        {
            sum[i]=sum[i-1]+a[i-1].x;
        }
        ll mskill;
        ll mk;
        ll ans=-1;
        int l,r;
        for(i=0,j=0;i<=n;++i)
        {
            ll p_cost=(n-i)*A-(sum[n]-sum[i]);//perfect需要消耗的货币
            if(p_cost>m) continue;
            ll left_cost=m-p_cost;//剩余的货币
            for(;j<i;++j)
            {
                if((ll)(j+1)*a[j].x-sum[j+1]>left_cost)
                    break;
            }
            if(j==0)//m的钱足够点满所有技能点
            {
                mskill=A;
            }
            else
            {
                --j;
                mskill=min(A,(sum[j+1]+left_cost)/(j+1));//minimum skill level不会超过A的限制
            }
            if(ans<mskill*cm+(n-i)*cf)
            {
                ans=mskill*cm+(n-i)*cf;
                l=j;
                r=i;
                mk=mskill;
            }
        }
        printf("%I64d\n",ans);
        for(i=0;i<n;++i)
        {
            if(i<=l)
            {
                a[i].x=mk;
            }
            else if(i>=r)
            {
                a[i].x=A;
            }
        }
        sort(a,a+n,cmp2);
        for(i=0;i<n;++i)
        {
            printf("%d",a[i].x);
            if(i!=n-1) printf(" ");
            else puts("");
        }
    }
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值