CodeForces 613 B.Skills(二分)

Description
有n项技能,每种技能有一个等级a[i],满级是A,攻击力的定义是满级技能数*cf+技能等级最小值*cm,现在有m个额外技能点,每个额外技能点可以使得一个还没满级的技能等价加一,问如果加点使得攻击力最大
Input
第一行五个整数n,A,cf,cm,m,之后n个整数a[i]表示每个技能的等级
(1<=n<=1e5,1<=A<=1e9,0<=cm,cf<=1000,0<=m<=1e15,0<=a[i]<=A)
Output
输出最大攻击力和加点后每个技能的等级
Sample Input
3 5 10 1 5
1 3 1
Sample Output
12
2 5 2
Solution
先把所有技能按等级升序排,对于没有满级的技能,从等级高到低逐个加满,每加满一个就二分等级最小值看拿剩余技能点可以把最低等级提升到多少,之后更新答案,时间复杂度O(nlogA)
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 111111
int n,A,cf,cm;
ll m;
struct node
{
    int v,id;
    bool operator<(const node &b)const
    {
        return v<b.v;
    }
}a[maxn];
bool cmp(node a,node b)
{
    return a.id<b.id;
}
int b[maxn];
ll sum[maxn];
int main()
{
    while(~scanf("%d%d%d%d%I64d",&n,&A,&cf,&cm,&m))
    {
        for(int i=1;i<=n;i++)scanf("%d",&a[i].v),a[i].id=i;
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++)b[i]=a[i].v;
        sum[0]=0;
        int pos=0;
        for(int i=1;i<=n;i++)
        {
            if(a[i].v!=A)sum[i]=sum[i-1]+a[i].v;
            else
            {
                pos=n-i+1;
                for(int j=i;j<=n;j++)sum[j]=sum[i-1];
                break;
            }
        }
        ll ans=0,ansm,ansf;
        for(int k=pos;k<=n;k++)
        {
            int nn=n+1-k;
            if(nn<=n)m-=A-b[nn];
            if(m<0)break;
            int l=0,r=A,mid,t=0;
            while(l<=r)
            {
                mid=(l+r)>>1;
                int pos=lower_bound(b+1,b+n+1,mid)-b-1;
                if(pos>=nn)pos=nn-1;
                ll temp=1ll*pos*mid-sum[pos];
                if(temp<=m)t=mid,l=mid+1;
                else r=mid-1;
            }
            if(1ll*t*cm+1ll*k*cf>=ans)
            {
                ans=1ll*t*cm+1ll*k*cf;
                ansm=t,ansf=k;
            }
        }
        for(int i=1;i<=n;i++)
        {
            if(a[i].v<ansm)a[i].v=ansm;
            if(n+1-i<=ansf)a[i].v=A;
        }
        sort(a+1,a+n+1,cmp);
        printf("%I64d\n",ans);
        for(int i=1;i<=n;i++)printf("%d ",a[i]);
        printf("\n");
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值