题意
有 (n) 个点,分别位于 ((x_i,y_i)),求最多能用两个长度为 (k) 的平台接住多少个点。
( exttt{Data Range:}nleq 2 imes 10^5,kleq 10^9)
题解
这是 Div.3 的 E 啊,为什么你们的写法都这么繁琐啊……
这题可以不用任何数据结构,甚至双指针都可以不用的啊,而且代码还短,为什么你们都不这样写啊
注意到 (y) 坐标没什么卵用,所以只需要考虑 (x) 坐标即可。
同时有一个结论:在某个最优的方案中两个平台的左端点一定与某一个点的 (x) 坐标一样。
如果不一样的话我可以将平台向右移来达到一样,右移过程中可能还会接到一些新的点,肯定不比之前的答案要差。
把所有点的 (x) 坐标从小到大排序,并且设 (f_i) 表示某个平台左端点为 (x_i) 的时候能接到多少个点。
我们考虑枚举最左边平台的左端点 (x_u),这个时候在这个平台右边 (x) 坐标最小不能接到的点一定是第 (u+f_u) 个。此时第二个平台的最大贡献就是 (f) 在 (u+f_usim n) 的最大值。
容易看出 (f) 可以直接指针扫就好了,而那个最大值其实就是后缀最大值,除去排序部分 (O(n)) 完事。
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=2e5+51;
ll test,n,kk,r,res;
ll x[MAXN],f[MAXN],mx[MAXN];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline void solve()
{
n=read(),kk=read();
for(register int i=1;i<=n;i++)
{
x[i]=read();
}
for(register int i=1;i<=n;i++)
{
read();
}
sort(x+1,x+n+1),r=1,res=0,f[n+1]=mx[n+1]=0;
for(register int i=1;i<=n;i++)
{
while(r<n&&x[r+1]-x[i]<=kk)
{
r++;
}
f[i]=r-i+1;
}
for(register int i=n;i;i--)
{
mx[i]=max(mx[i+1],f[i]);
}
for(register int i=1;i<=n;i++)
{
res=max(res,f[i]+mx[i+f[i]]);
}
printf("%d
",res);
}
int main()
{
test=read();
for(register int i=0;i<test;i++)
{
solve();
}
}