CF1409E Two Platforms

传送门

分析

本题的两个平台能否接住水滴仅与水滴的横坐标有关,所以纵坐标可以直接扔掉不管
小贪心:对于每一个水珠,显然,两个平台必须不能重合( 除非两个平台的总长度大于 \(n\) ),而且,平台若想要最大化接住的水滴数,显然平台的一个端点必然要接到至少一个水珠

那么,本题的解法就显然易见了:我们可以直接枚举每一个水珠的横坐标,计算以该水珠为起点的一个平台长度内一共能接到多少水珠,最后输出两个互不重合的平台能接到的水珠总数的最大值

Solution

显然,如果单纯的枚举与判断是至少要 \(O(nk)\) 的,会 T 得飞起,所以,我们考虑优化

我们要做的是找到区间长度为 \(k\) 内的数的个数,并不用计算数值大小,那么,我们可以进行离散化处理

对于每一段长度为 \(k\) 的区间,我们可以用利用前缀和预处理得到

如:

sort(a+1,a+n+1);
m=unique(a+1,a+n+1)-a-1;
for(int i=1;i<=n;i++)
{
      b[lower_bound(a+1,a+m+1,x[i])-a]++;//正常离散化
}
for(int i=1;i<=n;i++)
{
      pre[i]=pre[i-1]+b[i];//记录前缀和
}
for(int i=1;i<=n;i++)
{
      fg[i]=pre[upper_bound(a+i+1,a+m+1,a[i]+k)-a-1]-pre[i-1];
      //设平台起点横坐标为 i ,查找最后一个横坐标小于 i+k 的水珠的位置,利用前缀和做差快速求出该区间内一共有多少水珠
}

所以,我们可以再利用线段树,将另一块平台所能接到的最大水珠数量求出
node *rot=New(1,n);
for(int i=1;i<=m;i++)
{
      ans=max(ans,rot->qry(upper_bound(a+i+1,a+m+1,a[i]+k)-a,m)+fg[i]);
      //这里的fg[i]表示了点第一块平台所能接到的最大水珠数量
      //用线段树查询该平台末端以后的区间内,另一块平台所能覆盖到的最大水珠数量
}

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<math.h>
#define ll long long
using namespace std;

const ll maxn=2e5+10;
ll t,n,m,k,ans;
ll x[maxn],y[maxn],a[maxn],b[maxn],pre[maxn],fg[maxn];

struct node
{
	ll v,l,r;
	node *ls,*rs;
	
	inline void pushup()
	{
		v=max(max(v,ls->v),rs->v);
	}
	inline bool inrange(ll L,ll R)
	{
		return (L<=l)&&(r<=R);
	}
	inline bool outofrange(ll L,ll R)
	{
		return (l>R)||(r<L);
	}
	inline ll qry(ll L,ll R)
	{
		if(inrange(L,R)) return v;
		if(outofrange(L,R)) return 0;
		
		return max(ls->qry(L,R),rs->qry(L,R));
	}
};

node Mem[maxn<<1];
node *pool=Mem;

inline node *New(ll L,ll R)
{
	node *u=pool++;
	u->l=L;
	u->r=R;
	
	if(L==R)
	{
		u->v=fg[L];
		u->ls=u->rs=NULL;
	}
	else
	{
		ll M=(L+R)>>1;
		u->ls=New(L,M);
		u->rs=New(M+1,R);
		u->pushup();
	}
	return u;
}

int main(void)
{
	scanf("%lld",&t);
	
	while(t--)
	{	
		ans=0;
		
		scanf("%lld%lld",&n,&k);
		
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&x[i]);
			a[i]=x[i];
		}
		for(int i=1;i<=n;i++)
		{
			scanf("%lld",&y[i]);
		}
		
		for(int i=0;i<=n;i++) b[i]=pre[i]=fg[i]=0;
		sort(a+1,a+n+1);
		m=unique(a+1,a+n+1)-a-1;
		for(int i=1;i<=n;i++)
		{
			b[lower_bound(a+1,a+m+1,x[i])-a]++;
		}
		for(int i=1;i<=n;i++)
		{
			pre[i]=pre[i-1]+b[i];
		}
		for(int i=1;i<=n;i++)
		{
			fg[i]=pre[upper_bound(a+i+1,a+m+1,a[i]+k)-a-1]-pre[i-1];
		}
		
		node *rot=New(1,n);
			
		for(int i=1;i<=m;i++)
		{
			ans=max(ans,rot->qry(upper_bound(a+i+1,a+m+1,a[i]+k)-a,m)+fg[i]);
		}
		
		printf("%lld\n",ans);
	}
	
	return 0;
}

另外,要注意 \(lower_bound\)\(upper_bound\) 的使用

posted @ 2020-09-20 17:05  雾隐  阅读(150)  评论(0编辑  收藏  举报