洛谷P3028 [USACO10OCT]汽水机Soda Machine

题意翻译

为了满足fj所有的N(1<=n<=50000)头奶牛的需求,fj新买了一台汽水机。他想找到一个最完美的位置来安放它。

奶牛的牧场可以被表示为一个一维数轴,第i个奶牛被放牧的区间是[Ai...Bi](包含端点),fj可以把汽水机放在[1..1,000,000,000]。

因为奶牛们都懒得要死,她们想尽可能的少移动。她们希望汽水机被放在自己的放牧区间内。

遗憾的是,fj并不总能满足所有奶牛的要求,所以他想请你帮忙算出他能满足的奶牛数目

 

输入

4 
3 5 
4 8 
1 2 
5 10 

输出

3

 

根据观察,可以发现区间都非常大达到10^9如果直接暴力是O(10^9n)肯定会超时,所以我采用了离散化,将区间离散

这样可以把最大时间复杂度降低到O(n^2)

代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
inline int read(){
	int x=0,f=0;char s=getchar();
	while(!isdigit(s))f|=s=='-',s=getchar();
	while( isdigit(s))x=(x<<1)+(x<<3)+s-48,s=getchar();
	return f==0?x:-x;
}
const int N=5e4+10;
struct LSnode{
	int x,z,p;
	inline bool operator<(const LSnode &k)const{
		return x<k.x;
	}
}b[N<<1];int a[N<<1];
int n;
int sum[N<<1];
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		b[2*i-1].x=read();
		b[2*i  ].x=read();
		b[2*i-1].p=2*i-1;
		b[2*i  ].p=2*i;
	}
	sort(b+1,b+2*n+1);
	b[1].z=1;
	for(int i=2;i<=(n<<1);i++){
		if(b[i].x==b[i-1].x)b[i].z=b[i-1].z;
		else b[i].z=b[i-1].z+1;
	}
	for(int i=1;i<=(n<<1);i++)a[b[i].p]=b[i].z;
	int maxx=0;
	for(int i=1;i<=n;i++){
		for(int j=a[2*i-1];j<=a[2*i];j++)
			sum[j]++,maxx=max(maxx,sum[j]);
	}
	printf("%d\n",maxx);
	return 0;
}

但是这个时间复杂度是O(n^2)还是会超时两个点,所以我想可以在区间修改时优化一下

因为上面的代码每次修改都是要从左到右每一个点都+1,所以我们可以考虑用前缀和的方式优化,因此只需要在每个区间的其实点+1,在区间的结束点+1的位置上-1,统计时不断的加这个点的sum值就好了

AC代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
inline int read(){
	int x=0,f=0;char s=getchar();
	while(!isdigit(s))f|=s=='-',s=getchar();
	while( isdigit(s))x=(x<<1)+(x<<3)+s-48,s=getchar();
	return f==0?x:-x;
}
const int N=5e4+10;
struct LSnode{
	int x,z,p;
	inline bool operator<(const LSnode &k)const{
		return x<k.x;
	}
}b[N<<1];int a[N<<1];
int n;
int sum[N<<1];
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		b[2*i-1].x=read();
		b[2*i  ].x=read();
		b[2*i-1].p=2*i-1;
		b[2*i  ].p=2*i;
	}
	sort(b+1,b+2*n+1);
	b[1].z=1;
	for(int i=2;i<=(n<<1);i++){
		if(b[i].x==b[i-1].x)b[i].z=b[i-1].z;
		else b[i].z=b[i-1].z+1;
	}
	for(int i=1;i<=(n<<1);i++)a[b[i].p]=b[i].z;
	int maxx=0;
	for(int i=1;i<=n;i++){
		sum[a[2*i-1]]++;
		sum[a[2*i]+1]--;
	}
	int s=0;
	for(int i=1;i<=b[n<<1].z;i++)s+=sum[i],maxx=max(maxx,s);
	printf("%d\n",maxx);
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值