Canada Cup 2016

题意:

Alice 和 Bonnie在玩一个游戏,规则如下:

有n个栈,每个栈里有两张照片,每张照片有两个属性ai和bi,含义是,如果Alice拿了这张照片,那么她获得ai分数,如果Bonnie拿到这张照片那么她获得bi分数,以下简称Alice为A,Bonnie为B

这个游戏的最终目的,并不是要想办法让自己的分数最大,而是让自己的分数与对手分数的差值尽可能大。

当然,因为照片是放在栈里的所以只有当栈顶的那张照片被拿走后,才能拿栈底的那张照片


现在由A先手,AB轮流操作,每次可以选择任意拿走一张照片(前提是拿得到)或者不执行任何操作,游戏结束,当所有照片被拿完或是双方连续不操作。问在规则下,A得到的分数-B得到的分数的最大值是多少?


solution:

对同一个栈内的两张照片分析

不妨用四个数字a,b,c,d表示一个栈,代表第一张照片能给A贡献a分,B贡献b分,c,d类似

若a + b >= c + d,这时,无论双方谁先拿了这个栈栈顶的照片,谁都不会让自己的局势更劣

因为a - d >= b - c或是b - c >= d - a

但是如果反过来,a + b < c + d,难道AB都不愿意先手?

事实上,若a > d,因为a - d < c - b,虽然A先手拿这个栈的照片得到的收益不如后手,但是至少对自己的局势有所贡献,另一方面,这时候b - c < d - a < 0,如果B先手,承受的扣分会更严重一些,所以B绝对不会在这个栈先手。因此这个栈等价于一张价值(a-d,d-a)的照片,总是会被记入答案

同理,当b > c,这个栈等价于一张价值(c-b,b-c)的照片,且一定会被记入答案

如果上述两种情况都不发生,无论谁在这个栈先手,另一方总能通过马上在这个栈拿走栈底照片,让自己的局势更优,因此,谁都不会在这样的栈做任何操作

这样,就剩下那些a + b >= c + d的照片了,既然谁都希望在这样的栈先手,那当然是每次取价值最大的照片了

不过这个价值是考虑双方面的,把一张(a,b)的照片替换成(a+b,a+b),然后答案加上a-b

A取这张照片,a+b+a-b = 2a,B取这张照片,a-b-a-b = -2b

那么也就能维护了,开个堆或者排序一下,每次取最大

#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 1E5 + 10;
typedef long long LL;

int n;
LL ans;

priority_queue <LL> Q;

void Add(int x,int y)
{
	ans += 1LL*(x-y);
	Q.push(x+y);
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n;
	for (int i = 1; i <= n; i++) {
		int a,b,c,d;
		scanf("%d%d%d%d",&a,&b,&c,&d);
		if (a + b >= c + d) Add(a,b),Add(c,d);
		else if (a > d) ans += 2LL*(a-d);
		else if (b > c) ans += 2LL*(c-b);
	}
	LL cur = 1;
	while (!Q.empty()) {
		ans += cur*Q.top();
		Q.pop(); cur *= -1;
	}
	cout << ans/2LL;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值