解题思路:

  • 不能递归了,递归栈真的会炸。
  • 递推进行,不能常规地从左往右推,而应该从右往左推,即答案位于dp[0]。
  • 先讨论一般情况,dp[i]表达的是此位置能到达n-1位置所能得到的最大分数。那么对于任一位置i有:dp[i]=max(dpi+1:n1+v[i])dp[i] = max(dp_{i+1:n-1}+v[i])即i位置往后走的过程中所能选取可以到达n-1的最大分+当前位置的分数。
  • 再讨论边界,当i = n-1时,分数即是v[n-1],这里有个特例,当v[n-1] = 0时,应该特殊处理,因为在中间过程中如果走不下去dp值会变0,所以要加以区分。
#include<bits/stdc++.h>
using namespace std;
//一样的逻辑,这一版递归炸了
// int solve(vector<int> &v, int i,int n, vector<int> &dp){
//     if(dp[i] != -1) return dp[i];
//     if(i >= n-1) dp[i] = v[i];
//     else{
//         int tmp = -3;
//         if(v[i] > 0){
//             int flag = 0;
//             for(int j = 1; j <= v[i]; ++j){
//                 if (i+j == n-1){
//                     flag = 1;
//                 }
//                 tmp = max(tmp,solve(v, i+j, n, dp));
//             }
//             if (flag) dp[i] = v[i] + tmp;
//             else
//                 dp[i] = tmp == 0? 0: tmp+v[i];
//         }
//         else dp[i] = 0;  
//     }
//     return dp[i];
// }
int solve2(vector<int> &v, vector<int> &dp, int n){
    dp[n-1] = v[n-1];//当只有一个点时,cost=v[i]
    for(int i = n-2; i >= 0; --i){
        if(v[i] > 0){//当所进过的点的值>0时,应选取可以到达结果的最大分数作为结果。
            int flag = 0;
            int tmp = -3;
            for(int j = 1; j <= v[i]; ++j){
                if(i+j >= n-1){
                    flag = 1;//flag来标记最后一个值为0的情况。
                    tmp = max(tmp, dp[n-1]);
                    break;
                }
                tmp = max(tmp, dp[i+j]);//一般情况
            }
            if(flag) dp[i] = tmp + v[i];
            else dp[i] = tmp == 0? 0: tmp+v[i];
        }
        else dp[i] = 0;
    }
    return dp[0];
}
int main(){
    int n;
    cin>>n;
    vector<int> v(n);
    for(int i = 0; i < n; ++i){
        scanf("%d",&v[i]);
    }
    vector<int> dp(n, -1);
   int ans;
   ans = (n==0?0:solve2(v, dp, n));

    cout<<(ans == 0? -1: ans)<<endl;
    return 0;
}