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