题解CF1389B Array Walk
题意
有\(n\)个元素的数组,数组的值表示得分,最初从下标为\(1\)的位置开始,总共可以向左或者向右移动\(k\)次,且向左移动的总次数不能超过\(z\)次,求恰好走\(k\)次的最大得分。
思路
看到这题的第一思路就是\(dp\),因为每次移动只能向左右移动,所以这题是一道线性\(dp\)问题,那么接下来的问题就是如何设置参数以及如何写状态转移方程了。
我们可以发现\(n<10^5\),以及\(z\)的最大值为\(5\),于是就可以用二维\(dp\)去标记状态,\(dp[i][j]\)表示总共移动了\(i\)次、其中向左移动了\(j\)次的最大得分,其状态转移方程如下
$\large{dp[i][j]=dp[i-1][j]+a[i-j*2+1]}$
\(\large{dp[i][j]=max(dp[i][j],dp[i-1][j-1]+a[i-1-(j-1)*2])}\)
当前状态下位置的最大得分和他前一个位置有关,第一个转移方程是往右走的情况,第二个转移方程是往左走的情况,\(a\)数组表示走之后到达的位置的得分,两者取最大即为当前位置的最大得分,答案输出即为\(dp[k][i],0\le i \le z\)中的最大值
时间复杂度\(O(n)\),常数\(z\)很小。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,n,k,z,a[100005],dp[100005][10];
signed main()
{
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
//不需要memset也不能用,用了的话复杂度为O(tn)会TLE
cin>>n>>k>>z;
for(ll i=1;i<=n;++i)cin>>a[i];
dp[0][0]=a[1];//初始化dp数组
dp[1][0]=a[1]+a[2];
for(ll i=2;i<=n;++i)
{
for(ll j=0;j<=z;++j)
{
dp[i][j]=dp[i-1][j]+a[i-j*2+1];
if(j>0)dp[i][j]=max(dp[i][j],dp[i-1][j-1]+a[i-1-(j-1)*2]);
}
}//进行状态转移
ll ma=-1;
for(ll i=0;i<=z;++i)ma=max(ma,dp[k][i]);//最大值即为答案
cout<<ma<<endl;
}
return 0;
}

浙公网安备 33010602011771号