• Discrete Centrifugal Jumps CodeForces


    题意:

    给你n个数hi,你刚开始在第1个数的位置,你需要跳到第n个数的位置。

    1、对于i、j(i<j) 如果满足

    max(hi+1,,hj1)<min(hi,hj)

    max(hi,hj)<min(hi+1,,hj1)

    那么就可以从i直接一步跳到j位置

    2、如果j=i+1,那么也可以直接跳过去

    问你从第一个位置跳到第n个位置,最少需要跳多少次

    题解:

    我们设dp[i]表示:从第一个位置跳到第i个位置最小需要跳多少次

    我们最重要的就是找在[1,i-1]这个区间内的k,哪个位置可以跳到i位置以使得dp[i]尽可能小。如果暴力查找的话,那么复杂度就是O(n*n),看一下数据就知道TLE

    那我们就要用一种数据结构来使得找这个k,这里我们使用栈,为什么不使用队列,因为如果满足

    max(hk+1,,hi-1)<min(hk,hi)

    max(hk,hi)<min(hk+1,,hi-1)

    就可以从k一步跳到i,我们使用单调队列那么就是从头开始了。

    我们维护两个单调栈,一个非严格递增,另一个非严格递减

    我们在这里讨论非严格单调递增栈的维护过程:

    如果一个数vi在放入栈之前,判断得知hi>=h[r.top],那么就可以从r.top位置跳到i位置。

    这个时候有一个问题,如果你把栈中的一些元素pop掉了,但是这些元素还可以更新大于i的位置的dp值 这个时候会影响最后的结果吗?

    其实是不会影响的,因为如果hk在hi进行栈之前被pop掉了,那么hk肯定是小于hi的。如果hk可以更新hj的信息(i<j) 那么vk和vj中那个大的肯定会小于min(vk+1,vk+2...vj-1)。 那么这个时候我们看我们维护的另一个非严格下降序列,它会替我们考虑这个问题的

    所以这样实现起来其实是没有问题的

    代码:

    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    #include<algorithm>
    #include<stack>
    using namespace std;
    const int maxn=3e5+10;
    const int INF=0x3f3f3f3f;
    #define mem_(x) memset(x,INF,sizeof(x))
    int v[maxn],dp[maxn];
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&v[i]);
        }
        mem_(dp);
        stack<int>r;  //非严格递增
        stack<int>r2; //非严格递减
        r.push(1);
        r2.push(1);
        dp[1]=0;
        for(int i=2;i<=n;++i)
        {
            int flag1=0,flag2=0;
            while(r.size() && v[i]>=v[r.top()])
            {
                //printf("%d %d
    ",i,r.top());
                if(v[i]==v[r.top()]) flag1=1;  //如果栈里面有数字和vi相等,那么我们在下面的判断中就不能使用r.top
                dp[i]=min(dp[i],dp[r.top()]+1); //进行更新vi的值,因为题目要求vi和vj之间的数要小于两者中的最小值
                r.pop();
                //flag1=1;
            }
            if(r.size() && !flag1)
            {
                dp[i]=min(dp[i],dp[r.top()]+1);
            }
            r.push(i);
    
            while(r2.size() && v[i]<=v[r2.top()])
            {
                if(v[i]==v[r2.top()]) flag2=1;
                dp[i]=min(dp[i],dp[r2.top()]+1);
                r2.pop();
                //flag2=1;
            }
            if(r2.size() && !flag2)
            {
                dp[i]=min(dp[i],dp[r2.top()]+1);
            }
            r2.push(i);
        }
        printf("%d
    ",dp[n]);
        return 0;
    }
  • 相关阅读:
    java基础1
    display:inline
    运用<ul><li>做导航栏
    ul和li 基本用法分析(这里主要想学习怎么用在导航栏中)
    转换(旋转)transform
    典型相关分析
    相关性模型-相关系数
    拟合算法
    插值算法
    评估类模型之优劣解距离法Topsis模型
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/13757377.html
Copyright © 2020-2023  润新知