【题解】P2587 [ZJOI2008] 泡泡堂 [贪心]
好久没看到这么纯的 greed 了。
P2587 [ZJOI2008] 泡泡堂 - 洛谷 (luogu.com.cn)
不简单一点都不简单,难点是如何平衡分数,找到无后效性的那个方法。
考虑让我方获得最大分,对方队伍同理,最后输出被 2 * n 减就行。
首先确定我们的原则:能打赢就打,尽量把我方大的留到最后!
排序搞俩指针,每次我方的最大和最小值叫 a_mx,a_mn,对方的最大和最小值叫 b_mx,b_mn。
如果 a_mn > b_mn,美美 + 2。
再看如果 a_mx > b_mx,那也美美 + 2。
好了那剩下的不是平手就是打输了,就把 a_mn 去打 b_mx(能平手就 + 1)。
为什么?分析下:
如果是都打输,那不如去送,没毛病。
如果 a_mn = b_mn,那我方别人来打 b_mn 肯定会相同甚至更好,先让 a_mn 去送。
如果 a_mx = b_mx,如果 a_mx > 对方次大的,总体 + 0 + 2 比 + 1 好,送得好。
如果 a_mx = 对方次大的,那就接着送,直到出现上面的情况。
请看(请把上面的当自家队,下面的是 enemy):
3
4 5 5
4 5 5
如果大家都安安分分的打,能拿 3 分。
如果整活送,也能拿 3 分。
3
3 5 5
4 5 5
也都是 2 分。
3
3 3 5 5
3 4 5 5
而这样,我们投机取巧可以拿到 4 分!
因为我们只在小的要不起、大的相同的时候才送,横竖都有一个要不起,不如留着大的。
代码:
#include<bits/stdc++.h>
using namespace std;const int N = 1e5 + 10;
int aa[N], bb[N], n;int work(int a[], int b[]) {int al = 1, ar = n, bl = 1, br = n;int res = 0;for (int i = 1; i <= n; i ++) {if (a[al] > b[bl]) {al ++;bl ++;res += 2;}else if (a[ar] > b[br]){ar --;br --;res += 2;}else {if (a[al] == b[br]) {res ++;}al ++;br --;}}return res;
}int main () {ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i ++) {cin >> aa[i];}sort (aa + 1, aa + n + 1);for (int i = 1; i <= n; i ++) {cin >> bb[i];}sort (bb + 1, bb + n + 1);cout << work(aa, bb) << " ";cout << 2 * n - work(bb, aa);return 0;
}