迷之阶梯
Luogu P2433
题目描述
吴思宇 需要通过一段迷之阶梯。登上阶梯必须要按照它要求的方法,否则就无法登上阶梯。它要求的方法有以下三个限制:
如果下一步阶梯的高度只比当前阶梯高1,则可以直接登上。
除了第一步阶梯外,都可以从当前阶梯退到前一步阶梯。
当你连续退下 k 后,你可以一次跳上不超过当前 阶梯高度 2^k 的阶梯。
比如说你现在位于第 j步阶梯,并 且是从第j+k步阶梯退下来的。那么你可以跳到高度不 超过当前阶梯高度 + 2^k 的任何一步阶梯。
跳跃这一次只 算一次移动。
开始时吴思宇在第 1 步阶梯。
由于时间紧迫(急着~~,吴思宇需要计算 出登上迷之阶梯的最少移动次数。
输入输出格式
输入格式:
第 1 行:一个整数 N,表示阶梯步数;
第 2 行:N 个整数(每两个之间有 1 个空格),依次为每层阶梯的高度,保证递增。
输出格式:
输出格式
1 行,一个整数,如果能登上阶梯,输出最小步数, 否则输出-1。
输入输出样例
输入样例#1:
5
0 1 2 3 6
输出样例#1:
7
思路
这个题是一道动态规划,如果相邻阶梯差值为1,f[i]就可以从f[i-1]转移而来。
枚举从退到哪个点然后2^len跳过来,我们可以先求出这个len
len=ceil(log(a[i]-a[j])/log(2));前提是i-j>=len,因为从f[j+len]回退回来,这样f[i]就可以从f[j+len]转移而来,在f[j+len]基础上+len+1。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;
long long i,j,n,t,k,a[201],f[201],g[201];
long long r()
{
long long ans=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ans*=10;
ans+=ch-'0';
ch=getchar();
}
return ans*f;
}
int main()
{
n=r();
for(i=1;i<=n;i++)
{
a[i]=r();
g[i]=i;
}
for(i=n;i>=2;i--)
{
if(a[i]-a[i-1]==1)
{
g[i-1]=g[i];
}
}
memset(f,0x7f7f7f,sizeof(f));
f[1]=0;
int len=0;
for(i=1;i<=n;i++)
{
if(a[i]-a[i-1]==1)
f[i]=min(f[i],f[i-1]+1);
for(j=1;j<i;j++)
{
len=ceil(log(a[i]-a[j])/log(2));//需要回退多少下
if(j+len<=i)//回退下数
{
f[i]=min(f[i],f[j+len]+len+1);
}
}
}
if(f[n]!=9187201950435737471)
cout<<f[n];
else
cout<<-1;
return 0;
}
/*
6 3 6
1 0 1 0 1 1
1 1 1 1 0 0
0 0 0 1 0 1
0 0 1 1 1 1
*/