【简要题面】现在有n个形如(x,y)的二元组。支持如下两个操作:
1、x值加倍
2、y=x
现在支持a个1操作,b个2操作。求最大的 Σ y \Sigma y Σy
【分析】
有一个结论需要事先证明:对于一个人执行a次1操作,比对多个人执行a次操作要优。大致证明如下:
先假定有两个二元组分别进行过一次加倍后为(a,b)和(c,d)。(显然两个二元组都有a>b,c>d,不然就不需要证明了)
不妨设a>c,那么就有2*a+c/2大于a+c
根据上面的等式可以得到,对于一号二元组进行两次加倍要优于分开加倍。
多次同理,所以对于一个人加倍a次一定是最优的。
另一方面就要关系到赋值,给谁加倍是最优的?这一步我们枚举即可,但要进行一点优化:
先将二元组以x-y为关键字升序排序,这是不进行1操作时进行2操作的序列。
根据上面证明得到的结论,我们知道前b个二元组中只会有一个浮动。我们枚举加倍的二元组,再对预先统计好的总数进行微调即可。
【分析】
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=2e5+1000;
struct node{
int hp,dmg;
}arr[maxn];
int n,a,b,tmp,sum,mn=1e9,mx;
inline void read(int &x){
x=0;int fl=1;char tmp=getchar();
while(tmp<'0'||tmp>'9'){if(tmp=='-')fl=-fl;tmp=getchar();}
while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
x=x*fl;
}
bool cmp(node x,node y){
return (x.hp-x.dmg)>(y.hp-y.dmg);
}
signed main(){
freopen("match.in","r",stdin);
freopen("match.out","w",stdout);
cin>>n>>a>>b;a=1<<a;
for(int i=1;i<=n;i++)
read(arr[i].hp),read(arr[i].dmg);
sort(arr+1,arr+n+1,cmp);
for(int i=1;i<=b;i++){
sum+=max(arr[i].hp,arr[i].dmg);
mn=min(mn,arr[i].hp-arr[i].dmg);
}
for(int i=b+1;i<=n;i++)
sum+=arr[i].dmg;
mx=sum;
if(b>0){
for(int i=1;i<=min(b,n);i++){
tmp=sum;
tmp-=max(arr[i].hp,arr[i].dmg);
tmp+=max(arr[i].hp*a,arr[i].dmg);
mx=max(tmp,mx);
}
for(int i=b+1;i<=n;i++){
tmp=sum;
if(mn>0) tmp-=mn;
tmp-=arr[i].dmg;
tmp+=max(arr[i].hp*a,arr[i].dmg);
mx=max(tmp,mx);
}
}
cout<<mx<<endl;
return 0;
}