题解:AtCoder AT_awc0046_e A Walk and Barricades

【题目来源】

AtCoder:E - A Walk and Barricades

【题目描述】

Takahashi is taking a walk on a one-dimensional number line. Initially, Takahashi is at coordinate \(0\).
高桥正在一条一维数轴上散步。初始时,高桥位于坐标 \(0\)

Takahashi has \(N\) movement plans. Executing the \(i\)-th \((1 \leq i \leq N)\) plan adds \(D_i\) to his current coordinate. \(D_i\) is a non-zero integer; when positive, he moves in the positive direction, and when negative, he moves in the negative direction.
高桥有 \(N\) 个移动计划。执行第 \(i\) 个(\(1 \leq i \leq N\))计划会将他的当前坐标增加 \(D_i\)\(D_i\) 是一个非零整数;当为正数时,他向正方向移动;当为负数时,他向负方向移动。

There are \(M\) barricades placed on the number line. The \(j\)-th \((1 \leq j \leq M)\) barricade is at coordinate \(X_j\). When executing a plan moves Takahashi from his current coordinate \(s\) to coordinate \(s + D_i\), if there exists at least one barricade between \(s\) and \(s + D_i\) (inclusive of both endpoints), that is, if there exists an \(X_j\) satisfying \(\min(s,\, s + D_i) \le X_j \le \max(s,\, s + D_i)\), then a collision occurs and the plan cannot be executed.
数轴上放置了 \(M\) 个路障。第 \(j\) 个(\(1 \leq j \leq M\))路障位于坐标 \(X_j\)。当执行一个计划将高桥从当前坐标 \(s\) 移动到坐标 \(s + D_i\) 时,如果在 \(s\)\(s + D_i\) 之间(包含两端点)存在至少一个路障,也就是说,如果存在一个 \(X_j\) 满足 \(\min(s,\, s + D_i) \le X_j \le \max(s,\, s + D_i)\),则会发生碰撞,该计划无法执行。

Takahashi considers the plans in order from the \(1\)-st to the \(N\)-th. For each plan, if a collision would occur, he must skip that plan. If no collision would occur, he may freely choose to either execute or skip the plan.
高桥按顺序考虑第 \(1\) 到第 \(N\) 个计划。对于每个计划,如果会发生碰撞,他必须跳过该计划。如果不会发生碰撞,他可以自由选择执行或跳过该计划。

Find the maximum possible coordinate of Takahashi after all plans have been considered.
求在考虑完所有计划后,高桥可能达到的最大坐标。

【输入】

\(N\) \(M\)
\(D_1\) \(D_2\) \(\ldots\) \(D_N\)
\(X_1\) \(X_2\) \(\ldots\) \(X_M\)

  • The first line contains the number of plans \(N\) and the number of barricades \(M\), separated by a space.
  • The second line contains the coordinate changes \(D_1, D_2, \ldots, D_N\) for each plan, separated by spaces.
  • The third line contains the coordinates \(X_1, X_2, \ldots, X_M\) of each barricade, separated by spaces. However, if \(M = 0\), the third line is not given.

【输出】

Print in one line the maximum possible final coordinate of Takahashi when plans are chosen optimally.

【输入样例】

4 2
3 -2 4 -1
2 5

【输出样例】

0

【核心思想】

  1. 问题分析:高桥从坐标 \(0\) 出发,依次考虑 \(N\) 个移动计划 \(D_i\)(正数向右,负数向左)。数轴上有 \(M\) 个路障 \(X_j\),若执行某计划时移动路径(含端点)上存在路障,则必须跳过;否则可自由选择执行或跳过。坐标范围有限(\([-50000, 50000]\)),求最终可达的最大坐标。这是一个bitset 优化 DP问题,将可达坐标集合压缩为二进制位进行批量转移。

  2. 算法选择

    • bitset 状态压缩:用一个长度为坐标范围的 bitset 表示每个坐标是否可达,将 \(O(\text{坐标范围})\) 的集合操作转化为 \(O(\text{坐标范围} / 64)\) 的位运算
    • 阻塞位置预处理:对于每个计划 \(D_i\),利用路障 bitset 的移位操作,快速标记出所有"从此位置出发会碰撞路障"的起始点
  3. 关键步骤

    • 初始化
      • 读取 \(N\)\(M\)、计划数组 \(D[1..N]\)、路障数组 \(X[1..M]\)
      • 建立路障 bitset \(B\)\(B[X_j + \text{offset}] = 1\)(offset 用于处理负数坐标)
      • 建立可达 bitset \(dp\)\(dp[0 + \text{offset}] = 1\)
    • 处理每个计划 \(D_i\)
      • 计算阻塞位置 \(blk\)
        • \(D_i > 0\)(向右):对 \(j = 0\)\(D_i\),执行 \(blk \mathrel{|}= B \gg j\)。含义:若路障在 \(x\),则从 \(x-j\) 出发向右走 \(D_i\) 会经过该路障(当 \(0 \leq j \leq D_i\) 时)
        • \(D_i < 0\)(向左):取绝对值后,对 \(j = 0\)\(|D_i|\),执行 \(blk \mathrel{|}= B \ll j\)
      • 状态转移\(dp \mathrel{|}= ((dp \mathrel{\&} \sim blk) \ll D_i)\)(向右)或 \(\gg |D_i|\)(向左)
        • \(dp \mathrel{\&} \sim blk\):筛选出安全的起始位置
        • 移位操作:批量将所有安全起始位置移动到目标位置
        • \(dp \mathrel{|}=\):更新可达集合(保留之前可达的位置)
    • 输出答案:从大到小遍历坐标,找到 \(dp[\text{pos} + \text{offset}] = 1\) 的最大 pos
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \cdot (|D_i| + \frac{\text{坐标范围}}{64}))\)。对每个计划,计算阻塞位置需 \(O(|D_i| \cdot \frac{\text{坐标范围}}{64})\),bitset 移位和或操作需 \(O(\frac{\text{坐标范围}}{64})\)。由于坐标范围固定为 \(10^5\) 级别,可视为 \(O(N \cdot \frac{\text{MAX}}{64})\)
    • 空间复杂度:\(O(\text{坐标范围})\),即 \(O(\text{MAX})\),存储路障和可达状态两个 bitset
  5. bitset DP 的核心思想

    • 状态压缩:将一维布尔数组(可达/不可达)压缩为 bitset,使批量状态转移变为位运算,常数极小
    • 阻塞位置快速计算:通过路障 bitset 的多次移位和或运算,一次性标记所有危险起始点,避免对每个坐标单独判断
    • 坐标范围限制:本题坐标被限制在 \([-50000, 50000]\),使得 bitset 大小固定,保证了算法的可行性
    • 与状压 DP 的关系:本质是 DP 状态为"可达坐标集合",利用 bitset 将集合的并、移位操作并行化,是状态压缩思想在坐标型 DP 中的经典应用
    • 适用于坐标范围较小、状态为集合且转移为统一位移的 DP 问题

【算法标签】

状压DP

【代码详解】

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 50005, M = 200005;
int n, m;
int d[N], x[M];

signed main()
{
    cin >> n >> m;  // 输入n和m

    // 读取n个整数到数组d
    for (int i = 1; i <= n; i++)
    {
        cin >> d[i];
    }

    // 读取m个整数到数组x
    for (int i = 1; i <= m; i++)
    {
        cin >> x[i];
    }

    // 初始化bitset B,用于标记x[i]的存在
    // 偏移N=50005,使得负数索引变为正数
    bitset<M> B;

    // 将所有x[i]在[-50000, 50000]范围内的值标记在B中
    for (int i = 1; i <= m; i++)
    {
        if (-50000 <= x[i] && x[i] <= 50000)
        {
            B.set(x[i] + N);  // 设置对应位置为1
        }
    }

    // dp bitset,dp[i]表示是否能到达位置i
    // 初始位置设为0,偏移N
    bitset<M> dp;
    dp.set(N);  // dp[N]表示位置0

    // 动态规划:处理每个d[i]
    for (int i = 1; i <= n; i++)
    {
        bitset<M> blk;  // 阻塞位置集合

        if (d[i] > 0)  // 如果d[i]为正数,向右移动
        {
            // 计算阻塞位置:对于每个j∈[0,d[i]],B右移j位的位置都是阻塞的
            for (int j = 0; j <= d[i]; j++)
            {
                blk |= B >> j;  // 将B右移j位后的阻塞位置合并
            }

            // 状态转移:从可到达且不阻塞的位置向右移动d[i]位
            dp |= ((dp & ~blk) << d[i]);
        }
        else  // 如果d[i]为负数,向左移动
        {
            d[i] *= -1;  // 取绝对值

            // 计算阻塞位置:对于每个j∈[0,d[i]],B左移j位的位置都是阻塞的
            for (int j = 0; j <= d[i]; j++)
            {
                blk |= B << j;  // 将B左移j位后的阻塞位置合并
            }

            // 状态转移:从可到达且不阻塞的位置向左移动d[i]位
            dp |= ((dp & ~blk) >> d[i]);
        }
    }

    // 寻找最大可达位置
    int ans = 0;
    for (int i = -50000; i <= 50000; i++)
    {
        if (dp[i + N])  // 如果位置i可达
        {
            ans = i;  // 更新答案
        }
    }

    cout << ans << endl;  // 输出最大可达位置
    return 0;
}

【运行结果】

4 2
3 -2 4 -1
2 5
0
posted @ 2026-06-21 11:25  团爸讲算法  阅读(10)  评论(0)    收藏  举报