思路:二分枚举x。
#include <cstdio> using namespace std; const int MAXN = 10005; typedef long long LL; struct Rectangle{ int l, t, w, h; LL area; }rect[MAXN]; int R, n; LL sum; LL getArea(int x) { LL ret = 0; for(int i = 0; i < n; i++) { if(rect[i].l+rect[i].w <= x) { ret += rect[i].area; } else if(rect[i].l < x) { ret += ((LL)(x - rect[i].l) * rect[i].h); } } return ret; } int main() { int T; scanf("%d", &T); while(T--) { sum = 0; scanf("%d %d", &R, &n); for(int i = 0; i < n; i++) { scanf("%d %d %d %d", &rect[i].l, &rect[i].t, &rect[i].w, &rect[i].h); rect[i].area = ((LL)rect[i].w * rect[i].h); sum += rect[i].area; } if(sum == 0) { printf("%d ", R); continue; } //尽可能使x两边的oases的面积之和相等 int left = -1, right = R;//求right.将right初始化为可能的答案,left初始化为取不到的数值. while(right - left > 1) { int mid = (left + right) >> 1; LL sl = getArea(mid); LL sr = sum - sl; if(sl >= sr) { right = mid; } else { left = mid; } } //尽可能使x靠右 int s = getArea(right); left = right, right = R+1;//求left.将left去初始化为可能的答案,将right初始化为取不到的答案. while(right - left > 1) { int mid = (left + right) >> 1; if(getArea(mid) <= s) { left = mid; } else { right = mid; } } printf("%d ", left); } return 0; }
二分答案的过程中左右区间的划分问题。大于等于答案的最左值 mid = (left + right) >> 1; 小于等于答案的最右值 mid = (left + right + 1) >> 1;
#include <cstdio> using namespace std; const int MAXN = 10005; typedef long long LL; struct Rect{ int l, t, w, h; }rect[MAXN]; int n, R; LL sum; LL getArea(int x) { LL area = 0; for(int i = 0; i < n; i++) { if(rect[i].l + rect[i].w <= x) { area += ((LL)rect[i].w * rect[i].h); } else if(rect[i].l < x) { area += ((LL)rect[i].h * (x - rect[i].l)); } } return area; } int main() { int T; scanf("%d", &T); while(T--) { sum = 0; scanf("%d %d", &R, &n); for(int i = 0; i < n; i++) { scanf("%d %d %d %d", &rect[i].l, &rect[i].t, &rect[i].w, &rect[i].h); sum += ((LL)rect[i].w * rect[i].h); } int left = 0, right = R; while(right > left) { int mid = (left + right) >> 1; //求大于等于答案的最左值 LL s1 = getArea(mid); LL s2 = sum - s1; if(s1 >= s2) { right = mid; } else { left = mid + 1; } } LL tag = getArea(right); left = right, right = R; while(right > left) { int mid = (left + right + 1) >> 1; //求小于等于答案的最右值 if(getArea(mid) <= tag) { left = mid; } else { right = mid - 1; } } printf("%d ", left); } return 0; }