题意
选择k个不同位置+x,其他位置-x,求最大字段和
动态规划
我们设dp表示以i为结尾的最大字段和并且选择j个位置+x
那么我们可以分成三种情况
- 当 j = 0 时,即所有位置都不选,那么就是所有位置都减去x,根据常规的最大字段和dp即可,dp(i,j) = max(A[i] - x ,A[i]-x+dp(i-1,j))
- 接下来我们考虑取第i个位置的情况 ,那么如果前面i - 1结尾的字段和大于0那么取dp(i-1,j-1)一定是最优的,否则我们从0开始,可以得出 dp(i,j) = max(0,dp(i-1,j-1)) + A[i] - x
- 考虑不取第i个位置的情况,当前位置是需要 - x 的,那么dp(i,j) = max(0,dp(i-1,j)) + A[i] - x ,需要注意的是如果 i == j 时,此时是不合法的,因为当前不取的话,前i - 1个数字不可能选择 j个数
还需要注意的是j的枚举范围 是max(k-n+i,0) ~ min(i,k)
AC代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
typedef long long ll;
ll dp[N][21],A[N];
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T;
cin>>T;
while(T--){
ll n,k,x;
cin>>n>>k>>x;
for(int i = 1;i<=n;i++){
cin>>A[i];
for(int j = 0;j<=k;j++){
dp[i][j] = 0;
}
}
ll ans = -0;
for(ll i = 1;i<=n;i++){
for(int j = max(k-n+i,0ll);j<=min(i,k);j++){
if(j==0){
dp[i][j] = max(A[i]-x,A[i]-x+dp[i-1][j]);
}
else {
dp[i][j] = max(dp[i-1][j-1],0ll) + A[i] + x;
if(j < i) dp[i][j] = max(max(0ll,dp[i-1][j]) - x + A[i],dp[i][j]);
}
ans = max(ans,dp[i][j]);
}
}
cout<<ans<<'\n';
}
return 0;
}