您的位置:首页 > 其它

CodeForces 613 B.Skills(二分)

2017-04-20 14:49 357 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: