【洛谷 1929】迷之阶梯

题目描述

在经过地球防卫小队的数学家连续多日的工作后,外星人发的密码终于得以破解。它 告诉我们在地球某一处的古老遗迹中,存在有对抗这次灾难的秘密武器。防卫小队立即赶 到这处遗迹。要进入遗迹,需要通过一段迷之阶梯。登上阶梯必须要按照它要求的方法, 否则就无法登上阶梯。它要求的方法有以下三个限制:

  1. 如果下一步阶梯的高度只比当前阶梯高 1,则可以直接登上。

  2. 除了第一步阶梯外,都可以从当前阶梯退到前一步阶梯。

  3. 当你连续退下 k 后,你可以一次跳上不超过当前阶梯高度 2^{k}2k的阶梯。比如说你现 在位于第 j 步阶梯,并且是从第 j+k 步阶梯退下来的,那么你可以跳到高度不超过当前阶 梯高度+2^{k}2k的任何一步阶梯。跳跃这一次只算一次移动。

开始时我们在第一步阶梯,由于时间紧迫,我们需要用最少的移动次数登上迷之阶梯。 请你计算出最少的移动步数。

输入格式

第一行:一个整数 N,表示阶梯步数。

第二行:N 个整数,依次为每层阶梯的高度,保证递增。

输出格式

第一行:一个整数,如果能登上阶梯,输出最小步数,否则输出-1。

输入输出样例

输入 #1
5
0  1  2  3  6 
输出 #1
7

说明/提示

【样例解释】

连续登 3 步,再后退 3 步,然后直接跳上去。

【数据范围】

对于 50%的数据:1≤N≤20。

对于 100%的数据:1≤N≤200。

对于 100%的数据:每步阶梯高度不超过 2^31-1

 

题解:线性DP(当年我用dfs没过)

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
typedef long long ll;
using namespace std;
const int oo=0x3f3f3f3f;
const int N=222;
int n,a[N],f[N];
int main(){
    freopen("1929.in","r",stdin);
    freopen("1929.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    memset(f,0x3f,sizeof(f));
    f[1]=0;
    for(int i=2;i<=n;i++){
        if(a[i]<=a[i-1]+1)//当前位 
           f[i]=f[i-1]+1;
        for(int j=i-1;j>=1;j--)//上一位 
            for(int k=j-1;k>=1;k--)//后退几步 
                if( (1<<(j-k)) +a[k]>=a[i]) 
                   f[i]=min(f[i],f[j]+j-k+1);
    }
    printf("%d\n",f[n]>=oo?-1:f[n]);
    return 0;
}

 

posted @ 2019-11-01 16:28  #Cookies#  阅读(167)  评论(0编辑  收藏  举报