Educational Codeforces Round 144 (Rated for Div. 2)
D. Maximum Subarray
题意:给定三个整数 和一个长度为 的序列 。
我们要从这 个数中选出 个数把它的值加上 ,同时把其他没有选择的数字减去 。求进行该操作后的序列 的最大子段和。(同时注意考虑空的子段,其和为 0)
题解:
我们先把 都减去 ,现在只需要考虑加上 个 。
设 表示在 序列的 1 到 的位置上已加上了 个 的情况下,以 为结尾的最大子段和。
转移方程为:
f[i][j] = max({f[i - 1][j - 1] + a[i] + 2 * x, f[i - 1][j] + a[i], (LL)0});
需要注意几点:
1、当 时,不存在 所以取max的时候转移方程变成:
f[i][j] = max({f[i - 1][j - 1] + a[i] + 2 * x, (LL)0});
2、本题DP与其他动态规划最后取答案有别, 是在 序列的 1 到 的位置上已加上了 个 的情况下,还有 个位置需要加上 。所以当 时就应该计算答案。
具体代码如下:
#pragma GCC optimize(2)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <cmath>
#include <set>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#define int long long
#define quick_cin() cin.tie(0),ios::sync_with_stdio(false)
#define endl "\n"
#define pb push_back
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<LL, LL> PLL;
typedef pair<int, int> PII;
const int N = 200010, M = 110;
const int Mod = 1e9 + 7;
const int INF = 1e18;
int n, T, m, k;
int res;
int f[N][M];//以第i个数为结尾,前面加了j个x的最大字段和
int a[N];
int x;
void solve()
{
cin >> n >> k >> x;
for (int i = 1; i <= n; i ++ ) cin >> a[i], a[i] -= x;
res = 0;
for (int i = 1; i <= n; i ++ )
{
f[i][0] = max(f[i - 1][0] + a[i], (LL)0);
if (i <= n - k) res = max(res, f[i][0]);
for (int j = 1; j <= k && j <= i; j ++ )
{
if (i == j) f[i][j] = max(f[i - 1][j - 1] + a[i] + 2 * x, (LL)0);
else f[i][j] = max({f[i - 1][j - 1] + a[i] + 2 * x, f[i - 1][j] + a[i], (LL)0});
if (n - i + j >= k) res = max(res, f[i][j]);
}
}
cout << res << endl;
}
signed main()
{
quick_cin();
cin >> T;
// getchar();
// T = 1;
while (T -- )
{
solve();
}
return 0;
}