题意大概是可以将数列中值为零的数更改,求最终更改后的数组的前缀和为零的最大前缀和个数。
思路:令s=[a1,a1+a2,…,a1+a2+…+an],所以我们更改一个数a[i]后,硬性的前缀和有[si,si+1,…,sn],由于只能更改值为0的a[i],所以我们可以将所有前缀和分组:
- [s1,s2,…,si1−1]
- [si1,si1+1,…,si2−1]
- [si2,si2+1,…,si3−1]
- ……
- [sik,sik+1,…,sn]
每组(除了第一组)的头的下标都对应着a[i]=0,即我们需要改变的数,那么改变的原则是看此组中出现最多的数例如x则使a[i]=-x即可。
第一组是无法被改变的,所以第一组中只有0的个数可以贡献给最终答案
其实每改变一个数,后边的所有前缀和都要变,所以即使算出来的是x,也会在前几轮的更改中改变,但所有的改变都是统一的,不影响相同数的数目,并且只需求出个数即可,所以不必要每次改变后都更新,只需按照没更新前的数组计算即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
#define ll long long
int a[N];
map<ll, ll> sumnum;
int main()
{
int t;
cin >> t;
while (t--)
{
sumnum.clear();
int n;
cin >> n;
int flag = 0;
ll sum = 0;
ll ma = -1;
int ans = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
if (a[i] == 0)
{
if (flag)
ans += ma;
else
ans += sumnum[0];
flag = 1;
ma = 0;
sumnum.clear();
}
sum+=a[i];
ma=max(ma,++sumnum[sum]);
}
if(flag)
ans+=ma;
else
ans+=sumnum[0];
cout<<ans<<endl;
}
return 0;
}