标签:最优 最大子段和 题解 line 注意 输出 math 描述 整数
\(N\) 个整数组成的序列\(a[1],a[2],a[3],…,a[n]\),你可以对数组中的一对元素进行交换,并且交换后求 \(a[1]\) 至 \(a[n]\) 的最大子段和,所能得到的结果是所有交换中最大的。当所给的整数均为负数时和为0(即选取的字段可以为空)。
例如:\(\{-2,11,-4,13,-5,-2, 4\}\) 将 \(-4\) 和 \(4\) 交换,\(\{-2,11,4,13,-5,-2, -4\}\),最大子段和为 \(11 + 4 + 13 = 28\)。
第\(1\)行:整数序列的长度 \(N(2 <= N <= 50000)\)
第\(2\)行:\(N\)个整数(\(-10^9 <= A[i] <= 10^9\))
输出交换一次后的最大子段和。
7
-2 11 -4 13 -5 -2 4
28
注意边界问题的处理,不要出现负的下标等等
// 求第i个数向左延伸的最大子段和(向右的一样)
leftmaxsubsum[0] = 0;
lpos[0] = 0; // 记录向左延伸到的位置
for (int i = 1; i <= n; ++i) {
if (leftmaxsubsum[i - 1] + a[i] > 0) {
leftmaxsubsum[i] = leftmaxsubsum[i - 1] + a[i];
lpos[i] = lpos[i - 1]; // 如果直接拼接到前面,延伸到位置就是前面一个数延伸到的位置
} else {
leftmaxsubsum[i] = 0;
lpos[i] = 0; //如果一个数也不能延伸,相当于一个空字段,记为0
}
if (a[i] > 0 && lpos[i] == 0) lpos[i] = i; // 有可能前面的数不能延伸,但是a[i]大于0,那么相当于该子段只有它自己
}
// 枚举每个被替换的点
ll ans = 0, tmp;
ll l, r;
for (int i = 1; i <= n; ++i) {
// 先找到延伸到的边界
if (lpos[i - 1] == 0) { // 不能延伸的情况
l = leftmax[i - 1];
} else { // 能延伸的情况
l = leftmax[lpos[i - 1] - 1];
}
if (rpos[i + 1] == 0) {
r = rightmax[i + 1];
} else {
r = rightmax[rpos[i + 1] + 1];
}
tmp = leftmaxsubsum[i - 1] + rightmaxsubsum[i + 1] + max(l, r);
ans = max(ans, tmp);
}
标签:最优 最大子段和 题解 line 注意 输出 math 描述 整数
原文地址:https://www.cnblogs.com/kuangbiaopilihu/p/13097749.html