Codeforces Round #751 (Div. 1) B. Frog Traveler(思维题)

传送门

题意

你掉进了一个深度为n的井里,在深度为i的位置上,你可以最多跳\(a_i\)的高度,即你可以选择一个整数\(x\in [0, a_i]\),然后将高度变为\(i- x\)。你每次跳完后会休息一下,在第i个位置休息,你会下滑\(b_i\)高度,即高度变为\(i - b_i\),求最少多少次跳出井(坐标为0)。

\(1 \leq n \leq 300000\)

题解

这题vp的时候跳来跳去写晕了,写了一个搜索结果T了,官方题解写的又有点复杂,最后是在T的代码上将dfs改成bfs就过了。写篇题解来把思路理清楚。

这题如果以落下来后的位置设状态,很容易乱。因为一个极高处的点可能会落到一个很低处,于是导致状态的混乱。

但是我们可以以跳完后还未落下来的位置设置状态,对于一个相同的位置,它一定会落在一个固定的位置,我们就不管它会落在哪去了。

也就是说设dp[x]表示跳到x且还未落下来需要的次数。

我们自然希望dp[x]越小越好,如果之前有一个点比当前点能更快跳到x处,那么我们就不必考虑当前点跳到x位置了。

试着通过bfs求出所有dp值。因为每个点能跳跃的范围是一个连续的范围,所以我们依次从小到大枚举跳跃的值,最终已经遍历过的点能跳的范围一定构成一个连续的范围\([h,n]\),对于当前枚举的点我们只要考虑它是否能跳到比高度h小的位置,因为所有大于等于h的位置,前面已枚举过的点一定都能跳到而且根据bfs的性质,前面的点跳跃次数一定比当前枚举的点少。

因为每个点只会入队一次,时间复杂度为\(O(n)\)

代码

/*************************************************************************
> File Name: 1.cpp
> Author: Knowledge_llz
> Mail: 925538513@qq.com
> Blog: https://www.cnblogs.com/Knowledge-Pig/ 
************************************************************************/

#include<bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define LL long long
#define pb push_back
#define fi first
#define se second
#define pr pair<int,int>
#define mk(a,b) make_pair(a,b)
#define endl '\n'
using namespace std;
const int maxx = 5e5 + 10;
int n, a[maxx], b[maxx], dp[maxx], pre[maxx];
void bfs(){
    queue<int> q;
    q.push(n); dp[n] = 0;
    int h = n;
    while(!q.empty()){
        int x = q.front(); q.pop();
        // cout << x << endl;
        int y = x + b[x];
        for(int i = y - h + 1; i <= a[y]; ++i){
            q.push(y - i);
            dp[y - i] = dp[x] + 1;
            pre[y - i] = x;
            h = min(h, y - i);
        }

    }
}

int main(){
    ios::sync_with_stdio(false); cin.tie(0);
#ifndef ONLINE_JUDGE
    freopen("input.in", "r", stdin);
    freopen("output.out","w", stdout);
#endif
    cin >> n;
    memset(dp, 127, sizeof(dp));
    for(int i = 1; i <= n; ++i) cin >> a[i];
    for(int i = 1; i <= n; ++i) cin >> b[i];
    bfs();
    if(dp[0] == dp[n + 1]){ cout << -1 << endl; return 0; }
    cout << dp[0]<< endl;
    int x = 0;
    // return 0;
    stack<int> ans;
    while(x != n){
         ans.push(x);
         x = pre[x];
    }
    while(!ans.empty()){ cout << ans.top() << " "; ans.pop(); }
    return 0;
}
```C++
posted @ 2021-10-26 22:05  Knowledge-Pig  阅读(49)  评论(0)    收藏  举报