二分+贪心 hihocoder 1249 Xiongnu's Land (15北京A)

题目传送门

题意:有多个矩形分布在[0, 0]到[R, R]的的范围内,画一条竖线分割成两块矩形,使得左边包括矩形的面积大于等于右边的面积,在这个前提下使得画的竖线尽量远

分析:二分答案,当面积相等时,判断再往右一个单位是否还可以相等,若不行则答案唯一确定,否则可以往右移动,即最后的竖线要不在一个矩形内或者在矩形边缘时最优.

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1e4 + 10;
struct Point	{
	int x1, y, w, h, x2;
	bool operator < (const Point &r) const {
		return x1 < r.x1;
	}
}p[N];
int n, R;
ll tot;

ll cal(int mid)	{
	ll ret = 0;
	for (int i=1; i<=n; ++i)	{
		if (p[i].x1 >= mid)	break;
		else if (p[i].x2 <= mid)	ret += 1ll * p[i].w * p[i].h;
		else	{
			ret += 1ll * (mid - p[i].x1) * p[i].h;
		}
	}
	return ret;
}

bool check(int mid)	{
	for (int i=1; i<=n; ++i)	{
		if (p[i].x1 < mid && mid < p[i].x2)	return true;
	}
	return false;
}

int solve()	{	
	sort (p+1, p+1+n);
	int l = 0, r = R;
	while (l + 1 < r)	{
		int mid = (l + r) >> 1;
		ll LA = cal (mid);
		ll RA = tot - LA;
		if (LA < RA)	l = mid;
		else if (LA == RA)	{
			if (check (mid) || check (mid + 1))	{
				return mid;
			}
			else	l = mid;
		}
		else	{
			r = mid;
		}
	}
	if (check (r))	return r;
	for (int i=1; i<=n; ++i)	{
		if (p[i].x1 >= r)	return p[i].x1;
	}
	return R;
}

int main(void)	{
	int T;	scanf ("%d", &T);
	while (T--)	{
		scanf ("%d", &R);
		scanf ("%d", &n);
		tot = 0;
		for (int i=1; i<=n; ++i)	{
			scanf ("%d%d%d%d", &p[i].x1, &p[i].y, &p[i].w, &p[i].h);
			p[i].x2 = p[i].x1 + p[i].w;
			tot += 1ll * p[i].w * p[i].h;	//?
		}
		int ans = solve ();
		printf ("%d
", ans);
	}

	return 0;
}

  

编译人生,运行世界!
原文地址:https://www.cnblogs.com/Running-Time/p/4979690.html