对于这一题,主要利用前缀和,来做的,再利用map来记录是否出现过,如果出现过,则说明有一段为零,则答案加一,或者输入的数为零则同样满足,
代码如下
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
map<ll,ll>ms;//注意map要开到long long类型,不然会过不了
ll n,m;
int main()
{
cin>>n;
while(n--)
{
cin>>m;
ll k,sum=0;
ll ans=0;
for(ll i=1;i<=m;i++)
{
cin>>k;//输入值
sum+=k;//计算前缀和
if(sum==0||k==0||ms[sum]==1)//sum == 0:表示从序列开头到当前位置的子数组和为 0。k == 0:当前整数为 0,单独一个 0 就构成和为 0 的子数组。ms[sum] == 1:说明之前出现过相同的前缀和,意味着从上次出现该前缀和的位置到当前位置的子数组和为 0。
{
ans++;
sum=0;
ms.clear();//清空 map,为后续计算新的前缀和做准备。
}
else
{
ms[sum]=1;
}
}
cout<<ans<<endl;
ms.clear();//在处理每组新数据前,清空 map,避免上一组数据的影响。
}
return 0;
}
以样例2和3来演示一遍
2:
n = 2(剩余 2 组测试数据),进入第二组数据处理。
ms 清空。
m = 7(表示这组数据有 7 个整数)。
sum = 0,ans = 0。
遍历整数序列:
读取 12:
sum = 0 + 12 = 12。
因为 sum != 0,k != 0,ms[12] 未出现过,所以 ms[12] = 1。
读取 -4:
sum = 12 + (-4) = 8。
因为 sum != 0,k != 0,ms[8] 未出现过,所以 ms[8] = 1。
读取 4:
sum = 8 + 4 = 12。
满足 ms[12] == 1,ans = 1,sum = 0,ms 清空。
读取 43:
sum = 0 + 43 = 43。
因为 sum != 0,k != 0,ms[43] 未出现过,所以 ms[43] = 1。
读取 -3:
sum = 43 + (-3) = 40。
因为 sum != 0,k != 0,ms[40] 未出现过,所以 ms[40] = 1。
读取 -5:
sum = 40 + (-5) = 35。
因为 sum != 0,k != 0,ms[35] 未出现过,所以 ms[35] = 1。
读取 8:
sum = 35 + 8 = 43。
满足 ms[43] == 1,ans = 2,sum = 0,ms 清空。
输出结果:
输出 ans 的值,即 2。
3:
`n = 1(剩余 1 组测试数据),进入第三组数据处理。
ms 清空。
m = 6(表示这组数据有 6 个整数)。
sum = 0,ans = 0。
遍历整数序列:
读取 0:
满足 k == 0,ans = 1,sum = 0,ms 清空。
读取 -4:
sum = 0 + (-4) = -4。
因为 sum != 0,k != 0,ms[-4] 未出现过,所以 ms[-4] = 1。
读取 0:
满足 k == 0,ans = 2,sum = 0,ms 清空。
读取 3:
sum = 0 + 3 = 3。
因为 sum != 0,k != 0,ms[3] 未出现过,所以 ms[3] = 1。
读取 0:
满足 k == 0,ans = 3,sum = 0,ms 清空。
读取 1:
sum = 0 + 1 = 1。
因为 sum != 0,k != 0,ms[1] 未出现过,所以 ms[1] = 1。
输出结果:
输出 ans 的值,即 3。