嘘~ 正在从服务器偷取页面 . . .

CF875E Delivery Club 题解


CF875E Delivery Club 题解

题目链接:CF875E Delivery Club

题意

Petya 和 Vasya 是两个快递员。他们每天需要去 \(n\) 个地点送信,其中这 \(n\) 个点在同一条直线上。

由于公司内部的规定,送包裹必须按照某种特定的顺序依次送达。初始时 Petya 在位置 \(s_1\),Vasya 在位置 \(s_2\),并且送包裹的顺序为 \(x_1, x_2, \cdots, x_n\)

他们以如下形式送包裹:当前 \(i\) 个包裹均送达后,他们中的一个去送第 \(i+1\) 个包裹 (可以和送第 \(i\) 个包裹的人是同一个人,也可以是不同的人),另一个人则在原地等候。

由于他们需要互相交流,他们带了一对通讯设备。这对通讯设备在距离比较远时通讯功能较差。因此 Petya 和 Vasya 想找到一种合适的送包裹方案 (假如顺序是预先知道的),使得他们之间的最大距离尽可能的小。帮助他们确定在不违反规定的情况下,最大距离的最小可能值。

输入格式

第一行包含三个非负整数 \(n, s_1, s_2,~(1 \leq n \leq 10^5, 0 \leq s_1, s_2 \leq 10^9)\),表示送信地点的个数与 Petya 和 Vasya 的初始位置。

第二行包含 \(n\) 个非负整数 \(x_1, x_2, \cdots, x_n,~(x_i \leq 10^9)\),表示送包裹的规定顺序。

保证 \(s_1, s_2, x_1, x_2, \cdots, x_n\) 互不相同。

输出格式

输出一行一个整数,表示最大距离的最小可能值。

考虑二分这个最长距离 \(d\) ,然后判断能否成立。

仔细观察可以发现,

这两个快递员一定是一个在某个 \(x_i\) ,另一个去送下一个包裹(不一定是 \(x_{i+1}\) 哦)

在最长距离的约束下存在两个不同的可行域,分别对应这俩人能不能送下一个包裹

但是这个可行域由之前的决策决定,而我们不知道最优决策是什么。

考虑反推(可能叫逆向推理比较好)。

下文中记 \(A,B\) 以区分两个人,但是这个 \(A,B\) 是相对的两者。

注:其实就是「一个人」和「另一个人」,为了语言上便于区分加的记号

定义可行域 \(R_i\) 表示 \(A\) 送掉第 \(i\) 个包裹的后,\(B\) 应处于的位置。

可以发现在 \(A\) 送第 \(i\) 个包裹前,如果 \(B\) 不在 \(R_i\) 内,\(A\) 无法移动。

显然在 \(A\) 送掉第 \(n\) 个包裹的时候, \(B\) 的可行域为 \(R_n = [x_n-d,x_n+d]\)

注:你是否好奇为什么不能是 \(B\) 送掉最后一个包裹?

那说明你没有理解这个相对性。这里的 \(A\) 就是两者中的某个人, \(B\) 就是不同于他的那个人。

然后考虑 \(x_{n-1}\)

  • 如果 \(x_{n-1} \in R_n\) ,也就是第 \(n-1\) 个包裹在 \(B\) 的可行域

    那么我们直接让 \(B\) 来送掉第 \(n-1\) 个包裹就好了,然后让 \(A\) 送掉第 \(n\) 个包裹。

    因为当 \(B\) 送掉第 \(n-1\) 个包裹后,它在第 \(n\) 个包裹的可行域,于是 \(A\) 可以送第 \(n\) 个包裹

    故此时 \(A\) 的可行域为 \(R_{n-1} = [x_{n-1}-d,x_{n-1}+d]\)

    因为它要保证 \(B\) 能送掉第 \(n-1\) 个包裹。

  • 如果 \(x_{n-1} \not\in R_{n}\) ,也就是第 \(n-1\) 个包裹不在 \(B\) 的可行域

    这说明 \(x_{n-1}\) 肯定不能由 \(B\) 来送,只能由 \(A\) 来送。

    不然 \(B\) 送了第 \(n-1\) 个包裹后,\(A\) 无法送第 \(n\) 个包裹(别忘了假设哦)

    于是此时的情况就是 \(A\) 送掉第 \(n-1\) 个和第 \(n\) 个包裹。

    \(B\) 的可行域为 \(R_{n-1} = R_n \cap [x_{n-1}-d,x_{n-1}+d]\)

    因为它要保证在 \(A\) 能送掉第 \(n-1\) 个包裹(对应后面那个),并且要让 \(A\) 能送掉第 \(n\) 个包裹(对应前面的 \(R_n\) )。

不难发现这样的推理对于任意的 \(i \le n\) 都成立

于是我们通过归纳法得到了 \(A\) 送完第 \(1\) 个包裹后 \(B\) 的可行域 \(R_1\)

注:依旧不要忘了相对性。这里的 \(A\) 就是指某个人。

因为这个确实很绕,我自己写的时候都有点绕。

  • 如果 \(B\) 都不在 \(R_1\) 中,那么 \(A\) 是送不了第 \(1\) 个包裹滴,那么一定无解。

  • 如果 \(B\)\(R_1\) 中,因为 \(B\) 在送第 \(1\) 个包裹前后没有动

    所以还要保证 \(A\)\(B\) 在初始状态下距离不超过 \(d\) ,即 \(|s_1-s_2| \le d\)

然后对于过程中出现的空集(交集为空),一定无解。

否则一定存在某种方法使得这两个人可以送掉这些快递。

至此,我们做完了这题。

时间复杂度 \(O(n \log \max_{x_i})\)

代码:

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cstdarg>
#include <cmath>
#include <iomanip>
#include <random>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N ((int)(1e5+15))

int n,l,r,s1,s2,a[N];
void up(int &x,int y) { x < y ? x = y : 0;}
void down(int &x,int y) { x > y ? x = y : 0;}
bool work(int x)
{
    int l=a[n]-x, r=a[n]+x;
    for(int i=n-1; i>=1 && l<=r; i--)
        if(l <= a[i] && a[i] <= r) l=a[i]-x, r=a[i]+x;
        else up(l, a[i]-x), down(r, a[i]+x);
    return (l <= s1 && s1 <= r) || (l <= s2 && s2 <= r);
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> n >> s1 >> s2; 
    int l=min(s1,s2), r=max(s1,s2);
    for(int i=1; i<=n; i++) cin >> a[i], up(r,a[i]), down(l,a[i]);
    for(r-=l, l=abs(s1-s2); l<r; )
    {
        int mid = (l+r) >> 1;
        work(mid) ? r=mid : l=mid+1;
    }
    cout << l << '\n';
    return 0;
}

谁会想到这么简单的代码,却是这么难的题。


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录