Codeforces Round #281 (Div. 2) C. Vasya and Basketball 枚举+二分

思路:给定一个d,两队的分数可以在log(n)内求出:二分查找出最后一个不大于d的位置idx,则0~idx这idx+1次投球得分为2分,idx+1~n-1这n-idx-1次投球得分为3

所以只需枚举二分线d即可。开始时在最大最小值之间枚举,复杂度O(10^9)超时。观察数据量,其实枚举m+n个数即可。下面证明两者得到的最优解是等价的:

设最优解d,二分得到a队的位置为i (a[i] = x),b队的位置为j (b[j] = y) ,(d >= x,d >= y)。证明枚举到x和y时,其中覆盖了d的解

①若x > y,则枚举到x时,b[j + 1] > d >= x,a和b中的分界点与取d时相同

②若x = y,则枚举到x或y,都与d等价

③若x < y则枚举到y时,a[i + 1] > d >= y,a和b中的分界点与取d相同

特殊情况:由于从a、b的最小值枚举起,而d可能比二者的最小值还小,此时所有投球均取3分。

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
#define N 200005
int a[N], b[N], d[2 * N];

int binary_search(int x, int array[N], int bound){
	int l = 0, r = bound;
	while(l < r - 1){
		int mid = l + ((r - l) >> 1);
		if(array[mid] <= x)
			l = mid;
		else
			r = mid - 1;
	}
	if(array[r] <= x)
		return r;
	else if(array[l] <= x)
		return l;
	else
		return -1;
}

int main(){
	int n, m, len = 0;
	int ans, final1, final2;
	scanf("%d", &n);
	for(int i = 0; i < n; ++i)
		scanf("%d", &a[i]), d[len ++] = a[i];
	sort(a, a + n);
	scanf("%d", &m);
	for(int i = 0; i < m; ++i)
		scanf("%d", &b[i]), d[len ++] = b[i];
	sort(b, b + m);
	final1 = 3 * n, final2 = 3 * m, ans = final1 - final2;
	for(int i = 0; i < len; ++i){
		int idx1 = binary_search(d[i], a, n - 1);
		int idx2 = binary_search(d[i], b, m - 1);
		int score1 = (idx1 + 1) * 2 + (n - idx1 - 1) * 3;
		int score2 = (idx2 + 1) * 2 + (m - idx2 - 1) * 3;
		int tmp = score1 - score2;
		if(ans < tmp)
			ans = tmp, final1 = score1, final2 = score2;
		else if(ans == tmp && score1 > final1)
			final1 = score1, final2 = score2;
	}
	printf("%d:%d\n", final1, final2);
	return 0;
}


你可能感兴趣的:(枚举,codeforces,二分)