zoukankan      html  css  js  c++  java
  • AT2401 [ARC072C] Alice in linear land

    基于观察,可以发现这样一条性质:

    • 我们并不关心当前位置和终点的绝对关系,只在乎当前位置和终点的距离,当这个距离确定的时候接下来能走到的位置也是确定的。

    基于这个观察可以发现,本质上每个位置的状态就是和终点的距离。

    进一步可以发现,对于一个查询 (q = x) 假设在 (x - 1) 已经到达了 (p) 位置,那么我们一定可以在 (x) 这个位置通过调整使得经过 (x) 后距离终点的距离为 ([0, p]) 中任意一个数。

    于是问题就转化为,是否存在 ([0, p]) 中的一个距离 (d) 使得从 (x + 1) 开始往后走不能到达终点。

    可以发现,对于前者从 (1) 走到 (x - 1) 后距离终点的距离是很好计算的。

    直接令 (f_i) 表示 (1) 走到 (i) 后到终点的距离,则 (f_i = min(f_{i - 1}, |f_{i - 1} - a_i|))

    重头戏在后面部分,如何求出对于每个起点距离终点 (d)(i) 往后走能否到达终点呢?

    同样考虑直接令 (g_{i, j}) 表示起点距离终点 (j),从 (i) 往后走能否走到终点。

    那么就会有转移:

    [egin{aligned} g_{i, j} = egin{cases} g_{i + 1, j} (a_i >= 2 imes j) \ g_{i + 1, a_i - j} (j le a_i < 2 imes j) \ g_{i + 1, j - a_i} (a_i < j) end{cases} end{aligned} ]

    但是这样求是 (O(nD)) 的,显然不可取。

    可以发现,问题在于我们不能计算出所有的距离 (d) 是否能到达。

    于此同时又可以发现,我们并不需要知道所有的距离 (d) 是否能到达,只需要知道是否存在一个在 ([0, f_{i - 1}]) 内的距离即可。

    因此,为了尽可能满足在这个范围之内,我们只需要贪心地选取最小的哪个满足条件的距离,判断其是否在这个区间即可。

    顺着这个思路考虑改写一下所求,令 (g_i) 表示最小的距离 (d) 使得 (i) 往后不能到达终点。

    下面考虑转移,同样还是考虑分走或不走转移。

    继续观察可以发现 (forall i, g_i ge g_{i + 1}),因此为了使得 (g_i) 最小应该尽量使得其不走动。

    所以,当 (a_i ge 2 imes g_{i}) 时,(g_i = g_{i + 1}),因为我们只知道 (g_{i + 1}),因此判定条件改为 (a_i ge 2 imes g_{i + 1})

    那么当 (a_i < 2 imes g_{i + 1}) 时,(g_i ge g_{i + 1} + a_i);否则 (g_i < g_{i + 1} + a_i Rightarrow g_i - a_i < g_{i + 1}) 同时 (g_i - a_i) 也是不合法的,与 (g_{i + 1}) 已经最小矛盾。

    同时,这个下界显然是可以取到的,因此 (g_i = g_{i + 1} + a_i(a_i < 2 imes g_{i + 1}))

    显然初始值 (g_{n + 1} = 1)

    最后查询直接判断是否 (g_{q + 1} le f_{q - 1}) 即可,复杂度 (O(n + q))

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    #define rep(i, l, r) for (int i = l; i <= r; ++i)
    #define dep(i, l, r) for (int i = r; i >= l; --i)
    const int N = 5e5 + 5;
    const int inf = 1e9;
    int n, q, D, x, a[N], f[N], g[N];
    int read() {
        char c; int x = 0, f = 1;
        c = getchar();
        while (c > '9' || c < '0') { if(c == '-') f = -1; c = getchar();}
        while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    signed main() {
        n = read(), D = read();
        rep(i, 1, n) a[i] = read();
        f[0] = D, g[n + 1] = 1;
        rep(i, 1, n) f[i] = min(f[i - 1], abs(f[i - 1] - a[i])); 
        dep(i, 1, n) g[i] = (a[i] >= 2 * g[i + 1] ? g[i + 1] : g[i + 1] + a[i]);
        q = read();
        while (q--) x = read(), printf(g[x + 1] <= f[x - 1] ? "YES
    " : "NO
    ");
        return 0;
    }
    

    当要求某个范围内是否存在合法的数时,往往可以求某个特殊的合法的值,判断其是否在范围内即可。

    比如 ([0, x]) 内求最小,([x, +infty)) 求最大。

  • 相关阅读:
    1.border-image
    CSS3 3D transform
    js表单的focus()与blur()方法
    jquery背景backgroundPosition插件
    数字反转
    js的字符串charAt()方法
    FormData使用方法详解
    封装自己的jquery插件
    webpack打包vue项目之后怎么启动&注意事项
    JavaScript中的async/await
  • 原文地址:https://www.cnblogs.com/Go7338395/p/13866635.html
Copyright © 2011-2022 走看看