alt

解题思路:

这是一道动态规划的题目。要计算恰好移动k次获得的最大余额,我们可以设dp[i][j]表示走到第i格且恰好走了j次获得的最大余额,接下来让我们思考它的状态转移。

状态转移方程:

注意题目,每次可以走[1,6]的任意整数格,所以dp[i][j]只能由以下6种状态转移来:

  1. dp[i][j]=dp[i-6][j-1]+a[i]
  2. dp[i][j]=dp[i-5][j-1]+a[i]
  3. dp[i][j]=dp[i-4][j-1]+a[i]
  4. dp[i][j]=dp[i-3][j-1]+a[i]
  5. dp[i][j]=dp[i-2][j-1]+a[i]
  6. dp[i][j]=dp[i-1][j-1]+a[i]

只需由i-6到i-1逐个枚举即可。

AC代码

#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1e4+9;
const int M=2e3+7;
ll a[N],dp[N][M];//dp[i][j]表示到第i格且恰好走了j次的最大余额;
void solve()
{
    ll n,k;
    ll ans=-1e18;
    cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    memset(dp,-0x3f3f3f3f,sizeof dp);
    dp[0][0]=0;
    for(ll i=1;i<=n;i++)
    {
        for(ll j=1;j<=min(i,k);j++)
        {
            for(ll l=max(i-6,0ll);l<=i-1;l++)
            {
                dp[i][j]=max(dp[i][j],dp[l][j-1]+a[i]);
            }
        }
        ans=max(ans,dp[i][k]);
    }
    cout<<ans<<'\n';
}
int main()
{
    int _=1;
    while(_--)solve();
    return 0;
}

一些需要注意的细节:

  1. 因为题目所求为最大值,所以要将ans和dp数组的每个元素设为极小值,而dp[0][0]应该为0
  2. max和min函数的两个参数应该为同一类型,否则会报错
  3. 在第19行中,i-6有可能小于0导致越界,所以应该将其和0取一个最大值作为l的初值

总结

动态规划问题一般都需要确定状态和确定状态转移方程,找到各状态之间的关系一般为难点所在,同时对于初始化和边界问题也不容忽视