题目大意:
1 平面直角坐标系中,有n个矩形,要求用一个竖线:x=k,将空间分成左右两份:
2 要求1:左边的矩形面积和必须大于或者等于右边;
3 要求2:k值尽可能大(竖线尽量靠右);
解题思路:光看题目,感觉就是2个条件的二分查找,主要是存储优化,还有恶心的longlong。。。。,搞了我2个多小时!!
1 降维处理:题目给出的是矩形,可以将平面直角坐标系想象成坐标轴,所以每个x上就有一个值,表示对应的高度,用a数组来存储;
2 注意细节1:存储的位置和竖线的关系如下:(下图用的是样例数据)
解释上图:a数组存储的是竖格(矩形)的数量,答案记录的是竖线的值,所以只要这里没晕,就成功了一半;
3 用二分,可以算出要求1:左边和>=右边和,
4 注意细节2:二分结束后,还需要处理要求2:切线尽可能靠右!
特别鸣谢,本代码用了杭二建神的思想,将二分的终值设定成3个,最后进行特判,就不用在纠结“到底左边界还是有边界是答案呢?”这类无聊的问题了!
上代码:
//noi:1.11二分查找:03矩形切割
//在坐标系中,用竖线切割举行:
//1 要求左边一定要大于右边,差值尽可能小;
//2 要求左边尽可能大
#include<bits/stdc++.h>
#define ll long long
int a[1000005];
//a数组表示,在x=i的列上,有a[i]的高度
//将二维问题降低成一维问题考虑:
//题目变成了://有n个数字:
//1 左边和要求大于右边和,但是差值尽可能小
//2 左边的数字和尽可能大!
int n,m,ans;
//预处理出 a 数组
void pre()//二维->一维
{
scanf("%d %d",&m,&n);
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++)
{
int x,y,dx,dy;
scanf("%d %d %d %d",&x,&y,&dx,&dy);
for(int j=x;j<x+dx;j++)
{
a[j]+=dy;
}
}
}
ll che(int x)
{
ll s1=0;//左和
ll s2=0;//右和
for(int i=0;i<x;i++) s1+=a[i];
for(int i=x;i<m;i++) s2+=a[i];
return s1-s2;
}
int main()
{
pre();//输入与降维预处理
//二分代码
int l=0,r=m,mid;
while(l+3<r)//终值是从(l->r)这么多个数字
{
mid=(l+r)/2;
if(che(mid)>0) r=mid;
else l=mid;
}
//求出了符号条件的 l->r
ll su=999999999999;//因为 这个longlong,搞了2个小时!!!
for(int i=r;i>=l;i--)//对终值进行简单的判断
{
ll s=che(i);
if(s>=0&&s<su) {su=s; ans=i;}
}
//细节2:需要切线尽可能靠右
while(ans<m&&a[ans]==0) ans++;
printf("%d",ans);
return 0;
}