[CF1407D] Discrete Centrifugal Jumps

Description

给定一个序列,每次可以从 (i) 跳到 (j (>i)) 当且仅当满足以下三个条件之一:

  • (i+1=j)

  • (max(h[i+1,j-1])<min(h_i,h_j))

  • (min(h[i+1,j-1])>max(h_i,h_j))

求从下标为 (1) 的位置跳到下标为 (n) 的位置花费的最小步数。

Solution

考虑 dp,设 (f_i) 表示跳到第 (i) 个格子的最小步数,那么很显然 (f_i) 序列一定是单调的,这是由第一个转移条件保证的。

先考虑第二个条件,分析 (i) 状态可以从哪些状态转移过来。

维护一个单调递减的栈,那么有且仅有加入 (i) 的弹栈过程中经历的所有栈顶是合法的 (j)

所以我们只需要在加入 (i) 的过程中,对每次弹栈后的栈顶 (j),做一次 (j o i) 的转移即可。

对第三个条件也是同理的。

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

#define int long long 
const int N = 1000005;

int n;
int a[N],f[N];
int staAsc[N],topAsc,staDec[N],topDec;

signed main()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];

    f[0]=1e9;
    f[1]=0;

    staAsc[++topAsc]=1;
    staDec[++topDec]=1;

    for(int i=2;i<=n;i++)
    {
        f[i]=f[i-1]+1;

        while(topAsc && a[staAsc[topAsc]]>=a[i])
        {
            --topAsc;
            if(a[staAsc[topAsc+1]]==a[i]) continue;
            f[i]=min(f[i], f[staAsc[topAsc]]+1);
        }
        staAsc[++topAsc]=i;

        while(topDec && a[staDec[topDec]]<=a[i])
        {
            --topDec;
            if(a[staDec[topDec+1]]==a[i]) continue;
            f[i]=min(f[i], f[staDec[topDec]]+1);
        }
        staDec[++topDec]=i;
    }
    
    cout<<f[n]<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/mollnn/p/13842005.html