其他分享
首页 > 其他分享> > 【Codeforces Round #669 (Div. 2) D】Discrete Centrifugal Jumps

【Codeforces Round #669 (Div. 2) D】Discrete Centrifugal Jumps

作者:互联网

题目链接

点我呀

翻译

你在位置 \(1\),然后想要到位置 \(n\),每个位置都有一个高度 \(h[i]\), 你可以从位置 \(i\) 跳到位置 \(j\), 当且仅当以下情况之一满足:

问你从位置 \(1\) 跳到位置 \(n\) 最少需要跳多少次。

题解

刚开始在做这道题的时候,老想着对于每一个 \(i\) 会不会对应特别多的 \(j\)。

但其实我们可以这样想,假设我们现在要考察 \(x\) 能跳到哪个位置 \(y\),我们不妨先假设 \(x+1..y-1\) 这一段是全都大于 \(h[x]\) 和 \(h[y]\) 的,即我们翻译中的第三种情况。

那么我们分两类情况讨论:

\(x+1..y-1\) 这一段全都小于 \(h[x]\) 和 \(h[y]\) 的情况则类似, 也同样的是得到 \(x\) 和 \(y\) 对应的唯一的一个能跳到的位置。

经过上面的分析的话,不难发现每个位置 \(x\) 能够跳到的位置 \(y\) 其实最多只有 \(4\) 个。

注意到 左边最靠右的小于/大于 某个数的情况,和 右边最靠左的小于/大于 某个数的情况是一个经典的能用单调栈解决的问题(或者你也可以称呼它为只在一端操作的单调队列)。

这道题的话,每个位置需要从左往右维护上升下降栈,然后从右往左也同样要维护上升下降栈。

因此,对于每个位置 \(x\) 分别处理出来它能跳到的位置 \(y\),然后进行 \(dp\) 的转移即可 (\(dp_i\) 为到达位置 \(i\) 所需要的最少步骤数)。

最后输出 \(dp[n]\)。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 3e5;

int n;
int h[N + 10],incStack[N + 10],topInc,decStack[N + 10],topDec;
vector<int> g[N + 10];
int dp[N + 10];

int main(){
    #ifdef LOCAL_DEFINE
        freopen("E://9.AlgorithmCompetition//Visitor.txt","r",stdin);
    #endif
    ios::sync_with_stdio(0),cin.tie(0);
    cin >> n;
    for (int i = 1;i <= n; i++){
        cin >> h[i];
        if (i < n){
            g[i].push_back(i);
        }
    }
    topInc = 0,topDec = 0;
    for (int i = 1;i <= n; i++){
        while (topInc > 0 && h[incStack[topInc]] > h[i]) {
            topInc--;
        }
        //h[incStack[topInc]] <= h[i]
        if (topInc > 0){
            g[incStack[topInc]].push_back(i);
        }
        incStack[++topInc] = i;

        while (topDec > 0 && h[decStack[topDec]] < h[i]){
            topDec--;
        }
        //h[decStack[topDec]] >= h[i]
        if (topDec > 0){
            g[decStack[topDec]].push_back(i);
        }
        decStack[++topDec] = i;
    }

    topInc = 0,topDec = 0;
    for (int i = n;i >= 1; i--){
        while (topInc > 0 && h[i] < h[incStack[topInc]]){
            topInc--;
        }
        if (topInc > 0){
            g[i].push_back(incStack[topInc]);
        }
        incStack[++topInc] = i;

        while (topDec > 0 && h[i] > h[decStack[topDec]]){
            topDec--;
        }
        if (topDec > 0){
            g[i].push_back(decStack[topDec]);
        }
        decStack[++topDec] = i;
    }
    for (int i = 1;i <= n; i++){
        dp[i] = n + 10;
    }
    dp[1] = 0;
    for (int i = 1;i <= n; i++){
        int len = g[i].size();
        for (int j = 0;j < len; j++){
            int y = g[i][j];
            dp[y] = min(dp[y],dp[i] + 1);
        }
    }
    cout << dp[n] << endl;
    return 0;
}

标签:669,int,Jumps,位置,incStack,topInc,Centrifugal,decStack,topDec
来源: https://www.cnblogs.com/AWCXV/p/13640555.html