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

1 篇文章 0 订阅

给出一个数列,你每次可以讲其中任意一个数加一,但是你最多只可以操作m次,给出一个最大值A,每个数最多能加到A

然后所求的值是(最大值A的个数suma*cf加上整个数列最小值minf*cm)的最大值

cf的题基本上都是脑筋急转弯,首先我们可以枚举操作完后的最大值的个数,然后我们就会发现,如果你要一个值达到最大值的话,一定是从大到小来做,

假设 aj<ak<a

如果你将aj操作为最大值,就相当用ak到了最大值然后让aj变为ak,但是其实让aj变为ak并没什么意义ak-aj这段差距可以用来填最小值的坑,当然如果aj是最小值就去填aj了

所以我们排个序,然后从后往前枚举,从i+1->n都是A,然后从1->i使得最小值尽可能大。

至于最小值最大我用的是二分套二分


#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
long long n,A,cf,cm,m;
struct rec
{
	long long sum,h,wei,rank;
}skill[100100];
bool check(long long a,long long b,long long x,long long w)
{
	long long l=a,r=b,mid;
	while (l!=r)
	{
		mid=((l+r)>>1)+1;
		if (skill[mid].h>x) r=mid-1;
		else l=mid;
	}
	if ((l*x-skill[l].sum)<=w) return true;
	else return false;
}
long long work(int a,int b,long long w)
{
	long long l=skill[a].h,r=A,mid;
	while (l!=r)
	{
		mid=((l+r)>>1)+1;
		if (check(a,b,mid,w)) l=mid;
		else r=mid-1;
	}
	return l;
}
int cmp(rec a,rec b) {return a.h<b.h;}
int cmp2(rec a,rec b) {return a.wei<b.wei;}
int main()
{
	scanf("%I64d%I64d%I64d%I64d%I64d",&n,&A,&cf,&cm,&m);
	long long tot_m=m;
	for (int i=1;i<=n;i++)
	{
		scanf("%I64d",&skill[i].h);
		skill[i].wei=i;
	}
	sort(skill+1,skill+n+1,cmp);
	for (int i=1;i<=n;i++)
		skill[i].rank=i;
	for (int i=1;i<=n;i++)
		skill[i].sum=skill[i-1].sum+skill[i].h;
	if (n*A<=m+skill[n].sum) 
	{
		printf("%I64d\n",n*cf+A*cm);
		for (int i=1;i<n;i++)
			printf("%I64d ",A);
		printf("%I64d",A);
		return 0;
	}
	long long maxf=-1,ansl,ansr;
	for (int i=n;i;i--)
	{
		long long tmp=work(1,i,m);
		if (maxf<tmp*cm+cf*(n-i))
		{
			maxf=tmp*cm+cf*(n-i);
			ansl=tmp;
			ansr=i+1;
		}
		if (m+skill[i].h>=A) m-=(A-skill[i].h);
		else break;
	}
	printf("%I64d\n",maxf);
	sort(skill+1,skill+n+1,cmp2);
	for (int i=1;i<=n;i++)
	{
		if (skill[i].rank>=ansr)
		{
			tot_m-=(A-skill[i].h);
			skill[i].h=A;
			continue;
		}
		if (skill[i].h<ansl)
		{
			tot_m-=(ansl-skill[i].h);
			skill[i].h=ansl;
		}
	}
	for (int i=1;i<n;i++)
		printf("%I64d ",skill[i].h);	
	printf("%I64d",skill[n].h);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值