题意:
给一个数组,求它的子数组x,x的所有的子数组的和都不为0。输出x的个数, 子数组是原数组的子集,但是不能改变原数组的顺序。
思路:
这个题应该是用前缀和做,但是需要计数,计数就是最重要的事情。用一个map记录前缀和出现的最右位置。只要一个区间和为0了,那么这个区间后面的数,就肯定不行了。所有只需要考虑前面的。如果有前缀和已经出现过了,那么就说明区间的和为0了。
用L表示最右的左边界,每次计算需要增加的数(i-L)就可以了。
#pragma warning(disable:4996)
#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
ll a[200005];
map<ll, ll>mp;
int main()
{
ll i, j, n, sum, L, ans;
scanf("%lld", &n);
for (i = 1; i <= n; i++)
scanf("%lld", &a[i]);
sum = 0;
ans = 0;
mp[0] = 1;//把0标记为已经出现过
L = 1;
for (i = 2; i <= n + 1; i++)
//从2开始,因为mp[0]=1,需要往后移一位
{
sum += a[i-1];
if (mp[sum] != 0)
{
L = max(L, (mp[sum] + 1));
//取最大值
}
mp[sum] = i;
ans += (i - L);
}
printf("%lld\n", ans);
return 0;
}