1 条题解

  • 0
    @ 2026-6-19 10:31:05

    📝 题目大意

    (0,0)(0,0) 出发,每秒只能向上下左右移动一格(不能停留),给定 NN 个目标点 (xi,yi)(x_i, y_i) 和到达时刻 tit_i,判断能否按计划依次到达所有目标点。

    💡 解题思路

    1. 题目分析:这是一个判定性问题,关键在于两点之间的移动约束。数据范围 N105N \leq 10^5 要求 O(N)O(N) 解决。tit_i 严格递增,且 xi,yix_i, y_i 非负,但出发点 (0,0)(0,0) 在原点,无需特殊处理。

    2. 算法推导

      • (x1,y1)(x_1, y_1)(x2,y2)(x_2, y_2) 所需的最短时间就是曼哈顿距离:dist=x2x1+y2y1\text{dist} = |x_2 - x_1| + |y_2 - y_1|
      • 如果可用时间 dt=t2t1dt = t_2 - t_1 小于 dist\text{dist},则无法到达,直接输出 No
      • 如果 dtdistdt \geq \text{dist},多出的时间 extra=dtdist\text{extra} = dt - \text{dist} 必须被"浪费"掉。由于不能停留,唯一浪费时间的办法是来回走(例如向右走一步再向左走一步),每次来回消耗 2 单位时间。因此 extra\text{extra} 必须是偶数,即 (dtdist)mod2=0(dt - \text{dist}) \bmod 2 = 0
      • 本质上是坐标奇偶性的约束:曼哈顿距离与时间差的奇偶性必须一致。因为每次移动都会改变坐标和的奇偶性(x+yx+y 的奇偶性每步翻转),而时间每过 1 秒也会翻转一次,所以 ttx+yx+y 的奇偶性必须始终相同。
      • 代码实现:用 x1, y1, t1 记录上一个到达点的坐标和时间(初始为 (0,0,0)(0,0,0)),对每个新目标点计算 distdt,逐一检查两个条件。用标志 f 标记是否已经输出过 No,避免重复输出。
    3. 边界与细节

      • 题目保证 tit_i 严格递增,无需排序。
      • 注意 f 标志的使用:一旦判定为 No,后续输入仍需读入(否则会影响下一组数据的读取),但不再进行判断和输出,防止重复输出 No
      • 当所有检查通过后(f == 0),输出 Yes
      • 数据范围:ti,xi,yi105t_i, x_i, y_i \leq 10^5int 足够存储,不会溢出。

    ⏱️ 复杂度分析

    • 时间复杂度:对 NN 个目标点进行一次线性扫描,每次计算曼哈顿距离和奇偶性判断均为 O(1)O(1),总时间复杂度 O(N)O(N)
    • 空间复杂度:仅需存储 NN 个点的 t,x,yt, x, y 数组,以及几个辅助变量,总空间复杂度 O(N)O(N)

    💻 标准代码 (C++)

    #include <bits/stdc++.h>
    #define MAXN 200200
    #define MOD 998244353
    using namespace std;
    void solve(){
        int n;
        cin>>n;
        vector<int>t(n),x(n),y(n);
        int x1{0},y1{0},t1{0};  // 上一个到达点的坐标和时间,初始为原点时刻0
        int f{0};  // 标记是否已经输出过No,防止重复输出
        for(int i=0;i<n;i++){
            cin>>t[i]>>x[i]>>y[i];
            if(f)continue;  // 已经判定为不可行,跳过后续判断但仍需读入数据
            int dist=abs(x[i]-x1)+abs(y[i]-y1);  // 曼哈顿距离:最短所需时间
            // 条件1:可用时间不足以覆盖最短距离
            if(dist>t[i]-t1){
                cout<<"No"<<endl;
                f=1;
            }
            // 条件2:多余时间必须是偶数(来回消耗)
            if(((t[i]-t1)-dist)%2){
                cout<<"No"<<endl;
                f=1;
            }
            x1=x[i];  // 更新上一个到达点
            y1=y[i];
            t1=t[i];
        }
        if(!f)cout<<"Yes"<<endl;  // 所有检查通过
    }
    int main() {
        solve();
        return 0;
    }
    
    • 1

    信息

    ID
    846
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    (无)
    递交数
    1
    已通过
    1
    上传者