2 solutions

  • 1
    @ 2025-10-22 23:27:18

    这题的核心思想是把“跳跃 + 后退”转化成图上的最短路问题。 从第 i 个格子能跳到区间 [i+1, i+k[i]] 内的任意 j,然后落到 j−a[j] 上。 于是可以看成从 i 有边连向 (j−a[j])。每次跳跃的代价都是 1,所以整题就是求从 1 到 n 的最短路径,我们要用到BFS。 直接建图会超时,所以要用区间单调优化。 随着 BFS 按层推进,每个格子能跳到的右端总是单调不减的。我们用一个变量 maxs 记录当前已经扫描到的最右位置,每次只扩展还没访问过的新部分 [maxs+1, R],这样每个位置只会被处理一次,不会重复访问。 这个方法使压缩成线性扫描,整个 BFS 过程的时间复杂度降为 O(n)。

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    int n;
    int a[N], k[N], dist[N];
    
    int main() {
        ios::sync_with_stdio(false);
        cin.tie(nullptr);
    
        cin >> n;
        for(int i = 1; i <= n; i++) cin >> a[i];
        for(int i = 1; i <= n; i++) cin >> k[i];
    
        for(int i = 1; i <= n; i++) a[i] = i - a[i]; 
        fill(dist, dist + n + 1, INF);
        dist[1] = 0;
    
        queue<int> q;
        q.push(1);
    
        int maxs = 1;
        while(!q.empty()) {
            int u = q.front(); 
            q.pop();
            int r = min(n, u + k[u]);
            for(int j = max(maxs + 1, u + 1); j <= r; j++) {
                int v = a[j];
                if(v >= 1 && dist[v] == INF) {
                    dist[v] = dist[u] + 1;
                    q.push(v);
                }
            }
            maxs = max(maxs, r);
        }
    
        if(dist[n] == INF) cout << -1 << "\n";
        else cout << dist[n] << "\n";
        return 0;
    }
    
    

    Information

    ID
    43
    Time
    500ms
    Memory
    512MiB
    Difficulty
    3
    Tags
    # Submissions
    201
    Accepted
    32
    Uploaded By