Codeforces Round #674 (Div. 3) D

声明:本文学习自其他博客,原文链接 https://blog.csdn.net/qq_45585519/article/details/108861503.

D

题目链接: https://codeforces.ml/contest/1426/problem/D.
题目描述:
D. Non-zero Segments
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
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, 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
4
1 -5 3 2
output
1
input
5
4 -2 3 -9 2
output
0
input
9
-1 1 -1 1 -1 1 1 -1 -1
output
6
input
8
16 -5 -11 -15 10 5 4 -4
output
3
Note
Consider the first example. There is only one subsegment with the sum 0. It starts in the second element and ends in the fourth element. It’s enough to insert one element so the array doesn’t contain any subsegments with the sum equal to zero. For example, it is possible to insert the integer 1 between second and third elements of the array.

There are no subsegments having sum 0 in the second example so you don’t need to do anything.

题意 :就是给你一个序列,序列里不会有0,然后可以在任意两元素间插入任意数,让任意子序列和不为 0 。

解法:
区间和问题,一般都是用区间两端点的前缀和相减来解决的。
再思考一下,区间和为零,不就是两个前缀和相等嘛,当时思考到这,之后就想偏了。(不知道为啥就是没想出来)
(就一直在想怎么处理与前面的前缀和相等啊,一碰到相等的就答案加加之类的,就想着好多组不一样的相等前缀和咋整)
然后就无了
考完看题解,两个问题都给我解决了:
1.怎么处理多组相等的前缀和;
思考发现,如果碰到一组前缀和相等(即第一次找到一个区间为0) ,然后我们在右端点左边加入一个无穷大的值,那么这个时候就相当于加入这个值左面的所有子区间肯定不为 0了。所以我们就可以从当前的这个元素重新开始。就相当于一个新的前缀和是从目前这个从右端点开始计算的的,如此循环模拟,每次就只需要碰到相等的就答案++了,得到最少插入次数。
当然我们的前缀和只需要预处理,以便后面的新的前缀和可以维护一个变量,使得最初的前缀和减这个变量等于新的前缀和。
2.怎么判断有无相等的前缀和,在STL里有一个东西叫set
这个东西有个函数叫count,可以计算每个元素出现的次数,set里是不会出现重复元素的,所以每个前缀和加入set,并用count判断不就好了。没有这个数就加进去;有就ans++,然后处理新的前缀和。
AC代码:

#include 
#define maxn 200010
using namespace std;
typedef long long ll;
ll a[maxn],sum[maxn];

set<ll> s;
int ans = 0;
ll temp = 0;
int main()
{
	int n;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
    }
    sum[0]=a[0];
    for(int i=1;i<n;i++)
    {
        sum[i]=sum[i-1]+a[i];
    }
    //区间和即前缀和的差,区间和为0即有两个前缀和相等(由于不会出现元素为0)
    s.insert(0);
    for(int i=0;i<n;i++)
    {
        if(!s.count(sum[i]-temp)) s.insert(sum[i]-temp);
        else
        {
            ans++;
            s.clear();
            s.insert(0);
            s.insert(a[i]);//在区间右端点的左边插无穷大,所以目前这个得插入呀
            temp=sum[i-1];
        }
        
    }
    cout<<ans;

	return 0;
}

你可能感兴趣的:(acm,c++,算法)