题意:在一个二维坐标系中,给定一个矩形陆地,左下角坐标为 (0, 0)、右上角为 (R, R),在陆地中有 N 个矩形状的不重叠的绿洲,给出每个绿洲的左上角坐标 (L, T)、以及宽度 W 和高度 H。现在要你用 x = n ( n 为整数) 的一条竖线把整个陆地分成左 (left) 右 (right) 两部分,满足以下两个条件:
1)左边绿洲的总面积大于等于右边绿洲的总面积,并且绿洲面积差应尽可能小;
2)在满足第一个条件下,尽可能使得左边陆地的面积尽可能大。
分析:二分。在二分的过程中(我是左开右闭),如果左边绿洲面积等于右边绿洲面积,那么就要考虑当前 x = mid 以及 x = mid + 1 是否穿过了某些绿洲,如果穿过了的话,可想而知,该mid值即是结果,直接return mid即可,否则的话就按照二分的规则进行。这样得到最后结果是区间右边界 r,这里又是一个容易出错的地方,如果 x = r 的右边并没有任何绿洲的存在,那么应该得到的结果是 R,否则才是 r。这样子即可得到正解。
根据二分的性质,如果左边绿洲面积大于右边的时候,是一直减小右边界的。这里存在一种情况,如果最终结果就是左边绿洲面积大于右边,并且x = r 没有穿过任何绿洲,但是它右边连续的一段陆地并没有绿洲存在,那么结果应该往右移直到碰到一个绿洲结束,当然也有可能直到R。
题目链接:hihoCoder #1249
代码清单:
/*******************************************************************************
*** problem ID : A_Xiongnu's_Land.cpp
*** create time : Sun Nov 15 21:41:53 2015
*** author name : nndxy
*** author blog : http://blog.csdn.net/jhgkjhg_ugtdk77
*** author motto: never loose enthusiasm for life, life is to keep on fighting!
*******************************************************************************/
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <stack>
#include <ctime>
#include <vector>
#include <cctype>
#include <string>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
#define exit() return 0
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
const int maxn = 10000 + 5;
struct oasis { int L, T, W, H; };
int K;
int R;
int N;
oasis oa[maxn];
ll sumoa;
void input(){
sumoa = 0;
scanf("%d", &R);
scanf("%d", &N);
for(int i = 0; i < N; i++){
scanf("%d%d%d%d", &oa[i].L, &oa[i].T, &oa[i].W, &oa[i].H);
sumoa += ((ll)oa[i].W * (ll)oa[i].H);
}
}
ll getleft(int mid){ // 左边绿洲面积
ll ret = 0;
for(int i = 0; i < N; i++){
if(oa[i].L >= mid) break;
else if(oa[i].L + oa[i].W <= mid) ret += ((ll)oa[i].W * (ll)oa[i].H);
else ret += ((ll)(mid - oa[i].L) * (ll)(oa[i].H));
}return ret;
}
bool check(int mid){ // x = mid 是否穿过绿洲
for(int i = 0; i < N; i++){
if(oa[i].L < mid && oa[i].L + oa[i].W > mid) return true;
}return false;
}
bool cmp(oasis a, oasis b) { return a.L < b.L; }
int work(){
sort(oa, oa + N, cmp);
int l = 0, r = R, mid;
while(l + 1 < r){ // (l, r]
mid = (l + r) >> 1;
ll Left = getleft(mid);
ll Right = sumoa - Left;
if(Left < Right) l = mid;
else if(Left == Right){
if(check(mid) || check(mid + 1)) return mid;
else l = mid;
}
else r = mid;
}
//当 x = r 穿过了绿洲
if(check(r)) return r;
for(int i = 0; i < N; i++){
if(oa[i].L >= r) return oa[i].L;
}
return R;
}
void solve(){
printf("%d\n", work());
}
int main(){
scanf("%d", &K);
while(K--){
input();
solve();
} exit();
}