Codeforces Round #632 (Div. 2) C. Eugene and an array (思维,前缀和)

题目链接
**题意:**给一个数组a,他的子数组的定义为: a数组连续的片段(只要是连续的元素即可,可以为空或者直接是a数组全部)
如果这个子数组的子数组 (该定义与上面一样) 和不为0,也就是这个子数组中任意一个连续的片段和不为0。则称这个数组是符号条件的。
a的子数组中有多少个符号条件的。

思路(我只知道是前缀和。。没做出来,看了其他博主的文章,觉得有必要写一写,所以这里我会把我认为重要的地方写得细一点)
1.
首先我们知道a数组一共有n*(n+1)/2个子数组,那么我们可以推一下 : a数组 1 2 3 则从3往前面数 (我们现在假设元素3的数组下标为3) 则有 子数组 {3},{3,2},{3,2,1},从2开始数{2},{2,1},从1开始{1},那么我们发现了,该数组下标刚好与以这个元素为右端点的子数组总数相等。

2.
由1,我们可以找到方法怎么遍历了。
那么这里,就要讲另外一个东西了。我们这里不是要用前缀和吗?怎么用呢? 这里,你先想想,如果前3个数的前缀和与前5个数的前缀和相等,这说明了什么?最基本的反应是,这个数组中有负数或者零,再细想这俩个前缀相减等于0,而这俩个前缀相减又等于第四个数和第五个数相加。说明a数组的第四个元素和第五个元素相加等于0。那么任意的子数组要是包含了这一片段,就是不符合条件的。接下来,就是代码的实现过程了。

别人的AC代码。。。。

#include <bits/stdc++.h>
using namespace std;
#define NewNode (ListNode *)malloc(sizeof(ListNode))
#define Mem(a,b) memset(a,b,sizeof(a))
const int N = 2e5 + 50;
const int INF = 0x3f3f3f3f;
const double EPS = 1e-10;
const unsigned long long mod = 998244353;
const int II = 3.1415926535;
typedef long long ll;
typedef unsigned long long ull;
typedef pair <int,int> pii;
map<ll,ll> mp;
int main()
{
    std::ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    ll n,sum = 0,vis = 0,ans = 0;
    mp[vis] = 0;//mp记录,每个前缀和的下标(也就是前几个元素的和)
    cin >> n;
    for(int i = 1;i <= n;i++)
    {
        ll num;
        cin >> num;
        sum += num;//sum为前缀和
        if(mp.count(sum))//如果count返回1,说明,这个数在前面的前缀和中已经出现过了(也就是说,前面肯定有一个子片段和为0)。
            vis = max(vis,mp[sum]+1);//我们找到这个子片段的后一个元素,取max的原因是,防止vis大于mp[sum]+1。
        mp[sum] = i;//记录下标
        ans += i-vis;//i为以该点为右端点的子片段数,vis为,不符合条件的片段数
    }
    cout << ans << endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值