1 条题解
-
0
这里我先给出 的算法,它已经足够解决本题。然后,对于感兴趣的读者,我会展示如何实现 的解法。
方法
首先要注意的是,数据范围足够小,允许使用暴力枚举算法。我们可以计算每一种可能的单次操作后得到的 的数量,然后取最大值。
具体做法:用两个 FOR 循环枚举所有区间 (),这一步复杂度为 。对于每个固定的 和 ,我们需要计算执行翻转操作后 的个数
cnt。为此,我们再遍历一遍数组 ( 时间),总复杂度为 。对于每个下标 ,分两种情况:
- 如果 在区间 内(即 ),则该位置被翻转,因此向
cnt中添加 (注意: 变 , 变 )。 - 如果 不在区间内,则直接向
cnt中添加 。
最终答案为所有
cnt中的最大值。
方法
为了达到线性复杂度,我们需要做一个观察。假设我们翻转某个区间(可以是任意区间),并设 为翻转前数组中 的数量。那么翻转会发生什么?
- 每翻转一个 , 增加 (获得一个新的 )。
- 每翻转一个 , 减少 (失去一个 )。
我们定义翻转的“收益”:当遇到 时收益为 ,当遇到 时收益为 。由此我们可以构建一个新的数组 :
- 若 ,则
- 若 ,则
翻转后的 的数量为 ,其中 是区间 内 数组的和。由于 是常数,我们只需要最大化 。
换句话说,我们只需要在 数组中找到和最大的子数组(子序列要求连续)。翻转这个子数组对应的区间,就能得到最多的 。
找到最大和子数组可以用 Kadane 算法 在 时间内完成。如果你还不熟悉这个经典问题,建议先学习它,再回来看这个解法。
#include <iostream> using namespace std; int n,a,b=-1,s,q; main() { cin>>n; while(n--) { cin>>a; s+=a; q+=1-2*a; b=max(b,q); q=max(0,q); } cout<<s+b; } - 如果 在区间 内(即 ),则该位置被翻转,因此向
- 1
信息
- ID
- 6814
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 6
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者