【CF976E】match 比赛

【简要题面】现在有n个形如(x,y)的二元组。支持如下两个操作:

1、x值加倍
2、y=x

现在支持a个1操作,b个2操作。求最大的Σy\Sigma 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章