思路:二分枚舉x。spa
#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\n", 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\n", left); } return 0; }
二分答案的過程當中左右區間的劃分問題。大於等於答案的最左值 mid = (left + right) >> 1; 小於等於答案的最右值 mid = (left + right + 1) >> 1;code
#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\n", left); } return 0; }