CF-Round #632-div2-C题

CF-Round #632-div2-C题

C. Eugene and an array

传送门

这道题是思维,双指针~(嘻,又来到双指针啦)

题目大意:题目给定good子数组的含义。
如果此数组的任意的子数组的和都不为0,那么我们称这个数组为good数组。题目要求输出good数组的个数。

这道题首先想到的就是:先维护一波前缀和啦~
从前缀和的关系中维护我们的答案ans.
这个过程使用双指针。

自己模拟一下样例就很容易发现。要使得当前处理的数组中的子数组也是good数组的话。那么对应的前缀和也就不能出现重复的和。相同的前缀和对应到原数组中就是存在和为零的情况。
下标: 1 2 3 4
比如: 1 2 -3 1
前缀和:1 3 0 1
遇到相同的前缀和的时候比如sum[1]和sum[4],sum[4] - sum[1] = a[2] + a[3] + a[4] = 0;(前缀和相减是区间和,这个应该很容易)
这种情况是不满足要求的。所以我们让l++
l记录的是good数组左端对应的前一个下标
r记录的是good数组的右端对应的下标
所以初始化的时候l = 0, r = 1;(因为我存数据的时候是从1开始的哈)
用map来标记当前前缀和是否出现过。前缀和可能有正有负,所以不能用原先普通的数组。
map<ll, bool> vis;
首先初始化vis[0] = 1;
因为0是不允许出现的(不满足条件的)

最后我们维护一下ans:
ans += r - l就行。
对应的good数组为:
a[l + 1] ~ a[r];
a[l + 2] ~ a[r];
a[l + 3] ~ a[r];

a[r] ~ a[r];
一共(r - l)个。

代码部分很简洁~:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10;

ll sum[N];
map<ll, bool> vis;
int n;
 
int main()
{
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		ll t;
		scanf ("%I64d", &t);
		sum[i] = sum[i - 1] + t;
	}
	vis[0] = true;
	ll ans = 0;
	int l = 0, r = 1;
	while (r <= n)
	{
		while (vis[sum[r]])
		{
			vis[sum[l]] = false;
			l++;
		}
		vis[sum[r]] = true;
		ans += r - l;
		r++;
	}
	cout << ans << endl;
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

娃娃酱斯密酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值