CodeForces 1409E Two Platforms

题意

\(n\) 个点,分别位于 \((x_i,y_i)\),求最多能用两个长度为 \(k\) 的平台接住多少个点。

\(\texttt{Data Range:}n\leq 2\times 10^5,k\leq 10^9\)

题解

这是 Div.3 的 E 啊,为什么你们的写法都这么繁琐啊……

这题可以不用任何数据结构,甚至双指针都可以不用的啊,而且代码还短,为什么你们都不这样写啊

注意到 \(y\) 坐标没什么卵用,所以只需要考虑 \(x\) 坐标即可。

同时有一个结论:在某个最优的方案中两个平台的左端点一定与某一个点的 \(x\) 坐标一样。

如果不一样的话我可以将平台向右移来达到一样,右移过程中可能还会接到一些新的点,肯定不比之前的答案要差。

把所有点的 \(x\) 坐标从小到大排序,并且设 \(f_i\) 表示某个平台左端点为 \(x_i\) 的时候能接到多少个点。

我们考虑枚举最左边平台的左端点 \(x_u\),这个时候在这个平台右边 \(x\) 坐标最小不能接到的点一定是第 \(u+f_u\) 个。此时第二个平台的最大贡献就是 \(f\)\(u+f_u\sim 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\n",res);
}
int main()
{
    test=read();
    for(register int i=0;i<test;i++)
    {
        solve();
    }
}
posted @ 2020-09-26 19:46  Karry5307  阅读(198)  评论(0编辑  收藏  举报