提示:仅供参考
题目
一、分析
题目问的是最多的鸭鸭数量,也就是1的数量。首先我们不考虑魔法的使用,那么总重量应该就是所有编号为1的a[i]的重量相加,我们将这个命名为 ess(essential的缩写)作为基本量。然后对整个数组进行修改。
我们知道 在一段区间内进行修改,0 变为 1 的话会让 ess 增加,但是区间内会有1 变为 0 的情况 ,也就是可能有的鸭鸭会变成鼠鼠,那么就会让 ess 减少,对于一段区间内的变化,我们很容易想到刚学习过的前缀和知识,而且这是一维的,所以很简单。但是对于1变成 0 的情况,我们需要将其变为负数。对于样例二,也就是将原数组对应的1的5需要处理成-5。这样就完成了数组的处理,再进行前缀和,我们知道了任意区间长度的和,如果是正的,很明显可以增加鸭鸭的数量。
那么,我们就把问题转化为了求子区间和的最大值,这里我有两种算法(实际上还有很多),一种是贪心算法,一种是枚举r。对于贪心算法,我们采取的策略是,从头开始对处理后的原数组进行逐次增加,如果加到和为负数的时候,那么我们就舍弃掉这段,在下一个位置重新从零开始记录。代码留给大家思考,我在第三天的篇章开头给出答案。 对于枚举r,在每个情况内,prefix[r]是确定的,那么为了fix偏移量最大,那么就要求prefix[l - 1]最小,那么在遍历过程中进行存储即可。
二、代码展示
代码如下:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 10;
ll a[N],w[N],p[N];
int T;
void solve()
{
int n;
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= n; i ++) cin >> w[i];
ll fix = 0, ess = 0, mi = 0;
for(int i = 1; i <= n; i ++) ess += a[i] * w[i];
for(int i = 1; i <= n; i ++)
{
p[i] = p[i - 1] + (a[i] ? -1 : 1) * w[i];
fix = max(fix , p[i] - mi);
mi = min(mi, p[i]);
}
cout << ess + fix << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> T;
while(T --) solve();
return 0;
}