• Codeforces Round #632 (Div. 2) C. Eugene and an array 前缀和+计数


    https://codeforces.com/contest/1333/problem/C

    定义一个'good'数组:数组的子数组前缀和不为零;

    题目给定一个数组 a[i],求数组中满足'good'数组的子数组个数;

    做这题的时候忘了前缀和的一个性质(以前用到过),真tm傻逼啊,然后就一直不会,啊啊啊啊,这tm都不会,你不掉分谁掉分,掉分一时爽,一直掉分一直爽!!!

    看了别人代码模拟了一下,想起来了,,,,

    如果某个前缀出现了和前面一个前缀一样的和,那么中间的数的和为0;

    比如a1=1, a2=1, a3=2, a4=-3; sum[i] 为前缀和数组, sum[1]=1, sum[2]=2, sum[3]=4, sum[4]=1;

    sum[1]==sum[4], 那么 [2,4] 的区间前缀和为0.

    知道了这个性质就很简单了,用一个map数组维护当前出现过的前缀和的下标,用pos来记录当前没有前缀和为0的区间的左端点(pos要取max,如果有两个前缀和为0的数组成呈包含关系,例如 1,2,3,-5,-1,这个样例如果不取max就有问题),然后每次计算就可以了,满足条件的区间就是 [pos,i],然后区间内数的个数就是增加当前这个点后增加的'good'数组个数,注意一点边界问题。

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=2e5+5;
    const int mod=1e9+7;
    typedef long long ll;
    //typedef __int128 LL;
    const int inf=0x3f3f3f3f;
    const long long INF=0x3f3f3f3f3f3f3f3f;
    ll a[MAXN],sum[MAXN];
    map<ll,ll>mp;//mp记录前缀和的位置
    int main()
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld",&a[i]);
            sum[i]=sum[i-1]+a[i];
        }
        ll ans=0;
        ll pos=1;//pos记录前缀和不为零的区间左端点
        mp[0]=0;//把0记录下来,第一个数前面的前缀和为0
        for(int i=1;i<=n;i++)
        {
            if(mp.count(sum[i]))pos=max(pos,mp[sum[i]]+2);
            mp[sum[i]]=i;
            ans+=i-pos+1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    hdu1421 搬寝室(dp)
    HDU 2577(DP)
    扩展欧几里德算法
    unique函数的作用
    区间更新 zoj3911
    set的应用
    vue 事件处理器
    vue Class与style绑定
    vue的计算属性
    sass入门
  • 原文地址:https://www.cnblogs.com/MZRONG/p/12666912.html
Copyright © 2020-2023  润新知