【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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章