题意 :给你n个人的血量和伤害值,然后有两种操作:
1.将某一个人的血量翻倍 2.将一个人的伤害值等于其当前血量
你可以执行a次第一种操作和b次第二种操作,当然你不用非要执行完这a+b次操作,然后问你最终所有人的伤害值之和最大为多少?
一开始想难了,往dp上走了,但是无论如何都不知道怎么去掉第三层循环,后来突发奇想了一波,我第一种操作既然选择了一个人,呢我为什么还要再选择别人呢?可以证明,第一种操作一定是加在一个人身上最优,因此我们可以暴力第一种操作加在谁身上即可,剩下的我们可以按照血量-伤害值排序,然后让靠前的尽量的执行b操作即可。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
ll n,a,b,sum[200005],sm[200005];
struct node
{
ll x,y,z;
}val[200005];
bool comp(node a,node b)
{
return a.z>b.z;
}
int main(void)
{
ll ans=0;
scanf("%lld%lld%lld",&n,&a,&b);b=min(b,n);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&val[i].x,&val[i].y),val[i].z=val[i].x-val[i].y;
sort(val+1,val+n+1,comp);
for(int i=1;i<=n;i++)
{
sum[i]=sum[i-1]+max(val[i].x,val[i].y);
sm[i]=sm[i-1]+val[i].y;
}
ans+=sum[b]+sm[n]-sm[b];
if(b==0)
{
printf("%lld\n",sm[n]);
return 0;
}
if(a==0)
{
printf("%lld\n",ans);
return 0;
}
for(int i=1;i<=n;i++)
{
int num=0;ll t=val[i].x;
for(int j=1;j<=a;j++)
t*=2ll;
if(i<=b-1) t=t-max(val[i].x,val[i].y),t+=sum[b],t+=sm[n]-sm[b];
else t+=sum[b-1],t+=sm[n]-sm[b-1]-val[i].y;
ans=max(ans,t);
}
printf("%lld\n",ans);
return 0;
}