2015 Asia BeiJing Regional Contest A. Xiongnu's Land(二分)

来源:互联网 发布:java python学那个好 编辑:程序博客网 时间:2024/05/14 23:36


题意:在一个二维坐标系中,给定一个矩形陆地,左下角坐标为 (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 0typedef 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();}






0 0
原创粉丝点击