Codeforces Round #674 (Div. 3) D. Non-zero Segments(前缀和/尺取)垃圾做法
Kolya got an integer array a1,a2,…,an. The array can contain both positive and negative integers, but Kolya doesn't like 0 , so the array doesn't contain any zeros.
Kolya doesn't like that the sum of some subsegments of his array can be 0 . The subsegment is some consecutive segment of elements of the array.
You have to help Kolya and change his array in such a way that it doesn't contain any subsegments with the sum 0 . To reach this goal, you can insert any integers between any pair of adjacent elements of the array (integers can be really any: positive, negative, 00 0 , any by absolute value, even such a huge that they can't be represented in most standard programming languages).
Your task is to find the minimum number of integers you have to insert into Kolya's array in such a way that the resulting array doesn't contain any subsegments with the sum 0 .
Input
The first line of the input contains one integer n (2≤n≤200000) — the number of elements in Kolya's array.
The second line of the input contains n integers a1,a2,…,an(−109≤ai≤109,ai≠0) — the description of Kolya's array.
Output
Print the minimum number of integers you have to insert into Kolya's array in such a way that the resulting array doesn't contain any subsegments with the sum 0.
Examples
Input
Copy
4
1 -5 3 2
Output
Copy
1
Input
Copy
5
4 -2 3 -9 2
Output
Copy
0
Input
Copy
9
-1 1 -1 1 -1 1 1 -1 -1
Output
Copy
6
Input
Copy
8
16 -5 -11 -15 10 5 4 -4
Output
Copy
3
首先我们注意到如果某一子段i~j之和为0,那么由前缀和得sum[i - 1] = sum[j]。因此用map记录前缀和,这样就能直接把所有和为0的子段找出来。因为插入的数没有限制,所以可以将问题瞎JB转化为选最少的插入的位置覆盖所有的子段,类似紫书上讲的选最少的点覆盖所有的线段(贪心地尽可能取最右边),不过这个题还要稍微处理一下。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
int n, a[200005];
long long sum[200005] = { 0 };
map<long long, int> mp;
struct Segment
{
int x, y;
};
bool cmp(Segment a, Segment b)
{
if(a.y != b.y) return a.y < b.y;
else return a.x < b.x;
}
vector<Segment> v;
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
sum[i] = sum[i - 1] + 1ll * a[i];
}
mp[0] = 0;
for(int i = 1; i <= n; i++)
{
map<long long, int>::iterator it;
it = mp.find(sum[i]);
if(it != mp.end())
{
v.push_back(Segment{it->second + 1, i});
//mp.erase(it);
}
//else
mp[sum[i]] = i;
}
//LRJ 区间选点问题
sort(v.begin(), v.end(), cmp);
if(!v.size())
{
cout << 0;
return 0;
}
int ans = 1;
int p = v[0].y - 1;
for(int i = 1; i < v.size(); i++)
{
if(p < v[i].x)
{
ans++;
p = v[i].y - 1;
}
}
if(v.size() == 1) ans = 1;
cout<<ans;
return 0;
}