解题思路:
这是一道动态规划的题目。要计算恰好移动k次获得的最大余额,我们可以设dp[i][j]表示走到第i格且恰好走了j次获得的最大余额,接下来让我们思考它的状态转移。
状态转移方程:
注意题目,每次可以走[1,6]的任意整数格,所以dp[i][j]只能由以下6种状态转移来:
- dp[i][j]=dp[i-6][j-1]+a[i]
- dp[i][j]=dp[i-5][j-1]+a[i]
- dp[i][j]=dp[i-4][j-1]+a[i]
- dp[i][j]=dp[i-3][j-1]+a[i]
- dp[i][j]=dp[i-2][j-1]+a[i]
- 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;
}
一些需要注意的细节:
- 因为题目所求为最大值,所以要将ans和dp数组的每个元素设为极小值,而dp[0][0]应该为0
- max和min函数的两个参数应该为同一类型,否则会报错
- 在第19行中,i-6有可能小于0导致越界,所以应该将其和0取一个最大值作为l的初值
总结
动态规划问题一般都需要确定状态和确定状态转移方程,找到各状态之间的关系一般为难点所在,同时对于初始化和边界问题也不容忽视