思路:给定一个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;
}