P11743 Dynamic Array Problem题解
_InRedBrother_QWQ_ · · 题解
写作原因
一是为社区做贡献,
二是此题很有趣。
题意
题目描述地很详细,就不用复数了。
正解
由于要求一个元素至多被翻转一次,所以本题先可看作从长度为
由于数据范围
当然,这个值可不能用文中那个公式直接计算,毕竟内部翻转的子段
假设选择翻转或不翻转后的子段。
对于这个子段的最大值计算,可以。
- 从前往后;
- 从后往前。
从前往后
按照公式,一步步计算。
不过无法考虑中间插板是否有最优。
有 dalao 可以这样考虑最优的话请指教。
从后往前
我们考虑。
- 子段
[r, r] 。X_{0/1, r, r} = a_r; - 子段
[r - 1, r] 。X_{0/1, r - 1, r} = a_{r - 1} + 2 a_r; - 子段
[r - 2, r] 。X_{0/1, r - 2, r} = a_{r - 2} + 2 a_{r - 1} + 3 a_r; - ……
所以我们可以推出结论。
后面的
但如何保证子段的贡献最优呢?
我们可以先将答案更新,然后判断:如果
证明
设从
在这里插板子的贡献。
其中省略号表示已经处理过的部分。细节后半段,可以看出后者明显更优,因为后者比前者少了这么多:
而又已知
有个疑问:边界值
答:放在隔板之后。当和累加到
实现:
for(int i = 1; i <= n; i ++) {
X[0][i][i] = X[1][i][i] = A[i];
sum = A[i];
for(int j = i - 1; j >= 1; j --) {
sum += A[j];
X[0][j][i] = X[0][j + 1][i] + sum;
if(sum < 0) sum = 0;
}
sum = A[i];
for(int j = i + 1; j <= n; j ++) {
sum += A[j];
X[1][i][j] = X[1][i][j - 1] + sum;
if(sum < 0) sum = 0;
}
}
预处理完所有子段
考虑 DP。我们设数组
转移如下。
代码实现:
for(int i = 0; i <= n; i ++)
for(int k = 0; k <= K; k ++)
dp[i][k] = -MX;
dp[0][0] = 0;
for(int i = 1; i <= n; i ++) {
for(int k = 0; k <= min(K, i); k ++) {
for(int j = 0; j < i; j ++) {
if(-MX != dp[j][k]) dp[i][k] = max(dp[i][k], dp[j][k] + X[0][j + 1][i]);
if(k >= 1 && -MX != dp[j][k - 1]) dp[i][k] = max(dp[i][k], dp[j][k - 1] + X[1][j + 1][i]);
}
}
}
最终代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t = 1;
const int N = 605, MX = 0x3f3f3f3f3f3f3f3f;
int n, A[N], sum;
int K, ans = -MX;
int X[2][N][N], dp[N][N];
void solve() {
cin >> n >> K;
for(int i = 1; i <= n; i ++) cin >> A[i];
for(int i = 1; i <= n; i ++) {
X[0][i][i] = X[1][i][i] = A[i];
sum = A[i];
for(int j = i - 1; j >= 1; j --) {
sum += A[j];
X[0][j][i] = X[0][j + 1][i] + sum;
if(sum < 0) sum = 0;
}
sum = A[i];
for(int j = i + 1; j <= n; j ++) {
sum += A[j];
X[1][i][j] = X[1][i][j - 1] + sum;
if(sum < 0) sum = 0;
}
}
for(int i = 0; i <= n; i ++)
for(int k = 0; k <= K; k ++)
dp[i][k] = -MX;
dp[0][0] = 0;
for(int i = 1; i <= n; i ++) {
for(int k = 0; k <= min(K, i); k ++) {
for(int j = 0; j < i; j ++) {
if(-MX != dp[j][k]) dp[i][k] = max(dp[i][k], dp[j][k] + X[0][j + 1][i]);
if(k >= 1 && -MX != dp[j][k - 1]) dp[i][k] = max(dp[i][k], dp[j][k - 1] + X[1][j + 1][i]);
}
}
}
for(int k = 0; k <= K; k ++) ans = max(ans, dp[n][k]);
cout << ans;
}
signed main() {
// freopen("ex_box4.in", "r", stdin);
// freopen("box.in", "r", stdin);
// freopen("box.out", "w", stdout);
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
// cin >> t;
while(t --) {
solve();
}
return 0;
}
谢谢。