传送门
分析
本题的两个平台能否接住水滴仅与水滴的横坐标有关,所以纵坐标可以直接扔掉不管
小贪心:对于每一个水珠,显然,两个平台必须不能重合( 除非两个平台的总长度大于 (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
",ans);
}
return 0;
}
另外,要注意 (lower_bound) 与 (upper_bound) 的使用