openoj 矩形分割
- 总时间限制: 1000ms 内存限制: 65536kB
- 描述
-
平面上有一个大矩形,其左下角坐标(0,0),右上角坐标(R,R)。大矩形内部包含一些小矩形,小矩形都平行于坐标轴且互不重叠。所有矩形的顶点都是整点。要求画一根平行于y轴的直线x=k(k是整数) ,使得这些小矩形落在直线左边的面积必须大于等于落在右边的面积,且两边面积之差最小。并且,要使得大矩形在直线左边的的面积尽可能大。注意:若直线穿过一个小矩形,将会把它切成两个部分,分属左右两侧。 - 输入
- 第一行是整数R,表示大矩形的右上角坐标是(R,R) (1 <= R <= 1,000,000)。
接下来的一行是整数N,表示一共有N个小矩形(0 < N <= 10000)。
再接下来有N 行。每行有4个整数,L,T, W 和 H, 表示有一个小矩形的左上角坐标是(L,T),宽度是W,高度是H (0<=L,T <= R, 0 < W,H <= R). 小矩形不会有位于大矩形之外的部分。 - 输出
- 输出整数n,表示答案应该是直线 x=n。 如果必要的话,x=R也可以是答案。
- 样例输入
-
1000 2 1 1 2 1 5 1 2 1
- 样例输出
-
5
- 大致题意:有一个大矩形中有多个不相交的小矩形,要找一个 x 值使得在 x 左边的小矩形面积 >= 右面积(如果于 x 相切分为两半),并且保证大矩形左面积经可能的大。
- 思路:很明显这是根据小矩形左面积递增关系进行二分的题,不过这个边界条件比较特殊。分两种情况:
- 1.存在 == 这时只需要找到 == 的最右值;(二分 <= 最右端值)
- 2不存在 == 这时二分取到了 < 的最右值 但答案是刚好 > 的最右值;
1 while(l<=r){ 2 mid = md; 3 ll ant = fid(mid);//左边小矩形的面积 4 if(ant<vsum-ant) l = mid+1; 5 else r = mid-1; 6 } 7 ll cnt = fid(l); 8 while(cnt==fid(l)&&l<=n) l++;
- 再聊聊这个二分:这种二分写法参见 博客园 https://www.cnblogs.com/luoxn28/p/5767571.html
- 他的这种思路就是只考虑二分的最终结果,进而判断二分方向与结束时的取值。
- 大致讲一下
-
while(l<=r){ mid = md; ll ant = fid(mid);//左边小矩形的面积 if(ant<vsum-ant) l = mid+1;//在while中 l 是一直满足这个的 fid(l)<= key else r = mid-1; }//二分结束 l,r 的位置关系变成 r,l 这时 l 刚好不再满足while内的关系 //所以此时 l 刚好 > key 所以 r 为 <= 最右端的值
最后再讲一下这题的坑 long long
- 和一个偷懒的地方 求小矩形面积的时候提前把总面积求了,二分时只求一半。
- 下面是我的完整代码
-
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 #include <cmath> 6 #include <map> 7 #include <set> 8 #include <algorithm> 9 #define ll long long 10 #define md l+(r-l>>1) 11 #define max(a,b) (a<b?b:a) 12 #define min(a,b) (a<b?a:b) 13 using namespace std; 14 const int maxn = 1e5+500; 15 struct node{ 16 ll L,H,x; 17 }mp[maxn]; 18 int n,m; 19 ll vsum; 20 bool cmp(node a,node b){ 21 return a.x<b.x; 22 } 23 ll fid(ll t){ 24 ll sum = 0; 25 for(int i=0;i<m;++i){ 26 if(mp[i].x<t){//左边在 27 if(mp[i].x+mp[i].L<=t) sum+=mp[i].H*mp[i].L;//右边 28 else sum+=mp[i].H*(t-mp[i].x); 29 } 30 else break; 31 } 32 return sum; 33 } 34 int main(){ 35 while(~scanf("%d%d",&n,&m)){ 36 vsum = 0;int t; 37 for(int i=0;i<m;++i){ 38 scanf("%lld%d%lld%lld",&mp[i].x,&t,&mp[i].L,&mp[i].H); 39 vsum += mp[i].L*mp[i].H; 40 } 41 sort(mp,mp+m,cmp);//以小矩形的左纵边x 42 ll l=0,r=n,mid; 43 while(l<=r){ 44 mid = md; 45 ll ant = fid(mid);//左边小矩形的面积 46 if(ant<vsum-ant) l = mid+1; 47 else r = mid-1; 48 } 49 ll cnt = fid(l); 50 while(cnt==fid(l)&&l<=n) l++; 51 printf("%d\n",l-1); 52 } 53 return 0; 54 }
原文地址:https://www.cnblogs.com/DeadWooder/p/9526856.html
时间: 2024-11-13 02:48:21