【CF1333C】Eugene and an array(子区间计数)

传送门

  • 题目:
    在这里插入图片描述
  • 思路:
    枚举右端点,统计有多少个左端点和当前右端点组成的区间不是good,总数记为 c n t cnt cnt
    • 对于一个确定的区间 [ l , r ] [l,r] [l,r],如果 s u m [ r ] = s u m [ l − 1 ] sum[r]=sum[l-1] sum[r]=sum[l1],那么该区间内元素和为0, s u m [ ] sum[] sum[]表示前缀和。

    • 统计 s u m [ r ] sum[r] sum[r]最新出现的位置 p o s pos pos:

      • 如果 s u m [ r ] sum[r] sum[r]未出现过,那么不存在 l l l,使得 [ l , r ] [l,r] [l,r]的区间和为0,当前 r r r对答案的贡献即上一个 r r r对答案的贡献。
      • 如果 s u m [ r ] sum[r] sum[r]出现过,那么 [ p o s + 1 , r ] [pos+1,r] [pos+1,r]内的区间和为0,且对于 l ≤ p o s , [ l , r ] l≤pos,[l,r] lpos,[l,r]都是不是good。注意,可能出现 [ p o s + 1 , r ] [pos+1,r] [pos+1,r]内某个子区间和为0,且该子区间的左边界为 L L L,那么更新 L = m a x ( L , p o s + 1 ) L=max(L,pos+1) L=max(L,pos+1),当前 r r r对答案的贡献为 L L L
    • a n s = n ∗ ( n + 1 ) 2 − c n t ans=\frac{n*(n+1)}{2}-cnt ans=2n(n+1)cnt

  • ac代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const int maxn = 2e5+10;
int n;
ll  cnt[maxn];
map<ll, int> last;
int main()
{
    //freopen("/Users/zhangkanqi/Desktop/11.txt","r",stdin);
    scanf("%d", &n);
    ll x, sum = 0, ans = 0;
    int left0 = 0;
    last[0] = 0;
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld", &x);
        sum += x;
        if(!last.count(sum)) cnt[i] = cnt[i-1];
        else
        {
            left0 = max(left0, last[sum]+1);
            cnt[i] = left0;
        }
        last[sum] = i;
        ans += cnt[i];
    }
    printf("%lld\n", 1ll*n*(n+1)/2-ans);
    return 0;
}
/*
5
2 3 0 1 -4
8
2 3 0 1 2 1 -3 -4
 */
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值