#61sequence
题目传送门
分析
题目大意:给一个序列 A,你可以进行 k 次交换操作,最大化最大子段和,要输出方案有spj。
神仙数位Dp
首先交换这种东西一般就是放宽条件,变成有若干个数可以换出当前区间,若干个数可以换进当前区间,最后采用换进换出相同个数的数的状态即可。
f
[
i
]
[
p
]
[
q
]
[
r
]
f[i][p][q][r]
f[i][p][q][r]表示前
i
i
i个数,换进
p
p
p个数,换出
q
q
q个数,选择的子段和区间在当前位置
i
i
i的前面,中间,还是后面(
r
=
0
,
1
,
2
r=0,1,2
r=0,1,2)
考虑转移,需要大力讨论。
#Case1:r=1
当前
i
i
i在选择的区间之中。
有以下几种转移
- 接在上一个数的后面。 f [ i ] [ p ] [ q ] [ 1 ] = f [ i − 1 ] [ p ] [ q ] [ 1 ] + a [ i ] f[i][p][q][1]=f[i-1][p][q][1]+a[i] f[i][p][q][1]=f[i−1][p][q][1]+a[i]
- 之前一个数还没选,现在刚刚要选这个数: f [ i ] [ p ] [ q ] [ 1 ] = f [ i − 1 ] [ p ] [ q ] [ 0 ] + a [ i ] f[i][p][q][1]=f[i-1][p][q][0]+a[i] f[i][p][q][1]=f[i−1][p][q][0]+a[i]
- 上一个数还在选,但是不想选这个数,把一个数换进来替换它: f [ i ] [ p ] [ q ] [ 1 ] = f [ i − 1 ] [ p − 1 ] [ q ] [ 1 ] f[i][p][q][1]=f[i-1][p-1][q][1] f[i][p][q][1]=f[i−1][p−1][q][1]
- 上一个数还没选,也不想选这个数,但是想在这个位置开始选,仍然是把一个数换进来替换它: f [ i ] [ p ] [ q ] [ 1 ] = f [ i − 1 ] [ p − 1 ] [ q ] [ 0 ] f[i][p][q][1]=f[i-1][p-1][q][0] f[i][p][q][1]=f[i−1][p−1][q][0]
r = 1 r=1 r=1的情况讨论完了。注意换进来的数的贡献在后面统计。
#Case2:r=0,2
这个时候当前的位置是不选的,所以如果一个数想要有贡献一定得换走。
- 不想做任何动作: f [ i ] [ p ] [ q ] [ r ] = f [ i − 1 ] [ p ] [ q ] [ r ] f[i][p][q][r]=f[i-1][p][q][r] f[i][p][q][r]=f[i−1][p][q][r]
- 之前选,现在不选: f [ i ] [ p ] [ q ] [ 2 ] = f [ i − 1 ] [ p ] [ q ] [ 1 ] f[i][p][q][2]=f[i-1][p][q][1] f[i][p][q][2]=f[i−1][p][q][1]
- 把当前这个数换到可以选的某个位置: f [ i ] [ p ] [ q ] [ r ] = f [ i − 1 ] [ p ] [ q − 1 ] [ r ] + a [ i ] f[i][p][q][r]=f[i-1][p][q-1][r]+a[i] f[i][p][q][r]=f[i−1][p][q−1][r]+a[i]
- 之前选,现在位置不选,但是马上把这个数换走拿去充贡献: f [ i ] [ p ] [ q ] [ 2 ] = f [ i − 1 ] [ p ] [ q − 1 ] [ 1 ] + a [ i ] f[i][p][q][2]=f[i-1][p][q-1][1]+a[i] f[i][p][q][2]=f[i−1][p][q−1][1]+a[i]
其中
r
r
r表示
0
,
2
0,2
0,2都有这步转移,否则的话是由
1
−
>
2
1->2
1−>2
最后的答案就是
M
a
x
f
[
n
]
[
i
]
[
i
]
[
1
,
2
]
Max f[n][i][i][1,2]
Maxf[n][i][i][1,2]
输出
之所以定义如此麻烦的状态,就是因为其特别好输出。
考虑刚才的状态,实际上本质上都是两种请况。
- 有无分界点
- 有无交换
所以可以用一个两位2进制数来表示当前状态的选择是什么。
倒着扫一遍输出即可。
代码
#include<bits/stdc++.h>
#define rep(i, j, k) for(int i = j;i <= k; ++i)
const int N = 1e5 + 10, M = 11;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int n, m, a[N], pr, cu; char g[N][M][M][3], *B;
long long f[2][M][M][3], inf, *A;
void Tra(long long x, int c) {if(x > *A) *A = x, *B = c;}
int main() {
n = ri(); m = ri();
for(int i = 1;i <= n; ++i) a[i] = ri();
memset(f, -0x3f, sizeof(f)); memset(g, -1, sizeof(g));
inf = -f[0][0][0][0]; f[0][0][0][0] = 0; pr = 0, cu = 1;
for(int i = 1;i <= n; ++i, std::swap(cu, pr)) {
memset(f[cu], -0x3f, sizeof(f[cu]));
rep(j, 0, m) rep(k, 0, m) rep(l, 0, 2) {
A = &f[cu][j][k][l]; B = &g[i][j][k][l];
if(l == 1) {
Tra(f[pr][j][k][l] + a[i], 0);
Tra(f[pr][j][k][0] + a[i], 1);
if(j) Tra(f[pr][j - 1][k][l], 2);
if(j) Tra(f[pr][j - 1][k][0], 3);
}
else {
Tra(f[pr][j][k][l], 0);
if(l == 2) Tra(f[pr][j][k][1], 1);
if(k) Tra(f[pr][j][k - 1][l] + a[i], 2);
if(l == 2 && k) Tra(f[pr][j][k - 1][1] + a[i], 3);
}
}
}
long long Ans = -inf; int p, q, r, L, R = 0;
rep(i, 0, m) rep(j, 1, 2)
if(Ans < f[pr][i][i][j])
Ans = f[pr][i][i][j], p = q = i, r = j;
printf("%lld %d\n", Ans, p);
std::vector<int>x, y;
for(int i = n; i; --i) {
int c = g[i][p][q][r];
if(r == 1 && !R) R = i;
if(c & 2) {
if(r == 1) --p, x.push_back(i);
else --q, y.push_back(i);
}
if(c & 1) !--r ? L = i : 0;
}
for(int i = 0;i < x.size(); ++i) printf("%d %d\n", x[i], y[i]);
printf("%d %d\n", L, R);
return 0;
}