BZOJ 4925: 城市规划 差分

4925: 城市规划

Time Limit: 5 Sec  Memory Limit: 256 MB
Submit: 100  Solved: 49
[Submit][Status][Discuss]

Description

最近比特镇正在迅速建成。沿着美丽的大街,一座座新建筑拔地而起。小Q喜欢沿着大街走,但问题是不同的建筑位于街对面。为了从一个建筑到另一个建筑,有时需要通过漫长的步行穿过最近的人行道。所以他决定写一个程序,计算如何沿着大街平移所有人行道,使得人行道的布局最有利于行人。他希望尽可能多的人行道出现在某些建筑物的前面,同时人行道的移动距离应当是最小的。
大街以直线表示,人行道被视为这条线上的点。所有建筑物都平行于大街,所以你可以认为它们是直线上的一条条线段。每条线段都具有左边界和右边界。如果某人行道位于某建筑物的左右边界之间(包括边界点),则你可以认为该人行道位于该建筑物的前方。由于人行道已经按照某些标准建立,小Q决定保持它们之间的距离,所以他想将所有的人行道移动相同的距离。
请帮助小Q写一个程序计算最优布局

Input

第一行包含两个正整数n,m(1<=n<=10000,1<=m<=1000),分别表示人行道和建筑的个数。
第二行包含n个整数a_i(0<=a_i<=10^6),分别表示每条人行道的坐标,可能存在两条人行道重合。
接下来m行,每行两个整数l_i,r_i(0<=l_i<r_i<=10^6),分别表示每座建筑的左右边界,这些线段可以相互重叠。

Output

输出一行两个整数d和s,其中d表示平移距离的绝对值,s表示出现在至少一座建筑物前面的人行道个数。你需要输出s最大的解,若有多个d使得s最大,那么输出d最小的解。注意你可以向左或者向右平移人行道。

Sample Input

4 2
1 6 6 1
4 5
3 5

Sample Output

1 2

先把线段合并

然后以移动距离为下标把线段对于每个点差分

最后扫一遍就行了


疯狂卡常 最后也只能在内存上略胜一筹 抢个rank1 括弧泪

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<map>
#include<set>

using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=10100,M=1010;
const int MAXDIS=1e6+5;

struct seg{int l,r;}s[M];

inline bool cmp(const seg &x,const seg &y){return x.l<y.l;}

inline int tabs(int x){return x>0?x:-x;}

int a[N],ans[MAXDIS<<1];
int main()
{
	register int i,j,k,n=read(),m=read(),mx=0,D=MAXDIS,mn=0X3f3f3f3f,d,val=0,cnt=1;
	for(i=1;i<=n;++i)a[i]=read();
	for(i=1;i<=m;++i)s[i].l=read(),s[i].r=read();
	sort(s+1,s+1+m,cmp);
	for(i=2;i<=m;++i)
	if(s[i].l<=s[cnt].r)s[cnt].r=max(s[cnt].r,s[i].r);
	else s[++cnt].l=s[i].l,s[cnt].r=s[i].r;
	m=cnt;
	sort(s+1,s+1+m,cmp);
	for(i=1;i<=n;++i)for(j=1;j<=m;++j)
		{ans[s[j].l-a[i]+D]++;ans[s[j].r-a[i]+1+D]--;mx=max(s[j].r-a[i]+1+D,mx);mn=min(s[j].l-a[i]+D,mn);}
	for(i=mn;i<=mx;++i)
	{
		ans[i]+=ans[i-1];
		if(ans[i]>val)val=ans[i],d=tabs(D-i);
		else if(ans[i]==val)d=min(d,tabs(D-i));
	}
	print(d);putchar(' ');print(val);puts("");return 0;
}
/*
4 2
1 6 6 1
4 5
3 5

1 2
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值