题目链接


题目大意:

1 平面直角坐标系中,有n个矩形,要求用一个竖线:x=k,将空间分成左右两份:
2 要求1:左边的矩形面积和必须大于或者等于右边;
3 要求2:k值尽可能大(竖线尽量靠右);


解题思路:光看题目,感觉就是2个条件的二分查找,主要是存储优化,还有恶心的longlong。。。。,搞了我2个多小时!!

1 降维处理:题目给出的是矩形,可以将平面直角坐标系想象成坐标轴,所以每个x上就有一个值,表示对应的高度,用a数组来存储;
2 注意细节1:存储的位置和竖线的关系如下:(下图用的是样例数据)

noi1.11:03:矩形分割:二分+降维处理

解释上图: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;
}

 

相关文章: