先看题目:https://ac.nowcoder.com/acm/contest/5968/A
题目描述:
有n级台阶,在i级台阶可以走到i+1级台阶(仅h[i+1] == h[i]+1)时,也可以往下一级台阶到i-1级。如果连续下降k级台阶到达了第i级台阶可以上升到高度小于等于h[i]+2^k的任何一个位置。
解题思路:
定义状态f[i]为到达i级台阶的最小步数,枚举i,j,代表从某个台阶向下k级到达j级,k可以由ceil(log2(a[i]-a[j]))来求出,如果j+k < i,那么可以更新f[i]。为什么不再去考虑是向下走k+1级,k+2级...到达j的呢?这是因为f[i]一定是非递减的。因此f[j+k]+k+1肯定更优于f[j+k+1]+k+1+1...
你看,n^2dp就轻松解决啦,所幸有师哥的方法指导,否则脑残的我还在记忆化搜索debug。。。反思一下,这题为什么能for循环dp呢,虽然题目中说了可以从i+1级台阶下到i级台阶,但是完全没有必要啊...都已经能上到i+1了,当然也能到直接上到i了,完全不需要再‘绕路’,因此f[i]只需要由前面的更新得来。
代码:
#include<bits/stdc++.h> using namespace std; #define inf 0x3f3f3f3f int dp[210]; int a[210]; int main() { int n; scanf("%d",&n); memset(dp, inf, sizeof(dp)); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); } dp[1] = 0; for(int i = 2; i <= n; i++) { for(int j = 1; j < i; j++) { int k = ceil(log2(a[i]-a[j])); if(j+k < i) dp[i] = min(dp[i], dp[j+k]+k+1); } } printf("%d\n",dp[n] == inf ? -1 : dp[n]); }