【Eugene and an array】前缀和+尺取法 CF#632,C题

Eugene and an array

链接:C题链接
当时没想出来答案!(自己太菜了),看了一些分析后写了一下。
题意

一个good数组的定义:非空,并且其所有连续非空子数组的和都不等于0
子数组:一个数组本身,或者一个数组中的连续一段的数组,或空数组
比如[0] 不是good数组
[1,-1,5] 不是good数组因为其一个子数组[1,-1]和为0
[1,5,-1] 是good数组
现在给你一个长度为n的数组,求出有多少个good的子数组
数据范围:
1<= n <=2e5
-1e9<= ai <=1e9

思路:

首先所有子序列个数n^2 枚举肯定TLE呀!
关于一段序列长度的和,我们可以想到使用前缀和数组pre[],其中
pre[x]=arr[1]+aar[2]+……+aar[x]

然后我们在运算的时候如果存在pre[a]=k , pre[b]=k (1<=a<b<=n),
i.e. pre[b] - pre[a] = arr[b] + arr[b-1] + …… + arr[a+1] = k - k = 0
也就是区间 Sum[a+1 , b] = 0
那么区间[p,q] , (1<=p<=a+1 , b<=q<=n)是not good的
我们使用map<ll,bool>vis 映射,记录是否存在过pre[i]
代码实现就是如果当前区间中vis[pre[i]]==1了,表示之前存在过pre[i]了

但是这个区间的头和尾都不固定,不好办呀,那我们在算的时候让一端先固定,比如计算头是p尾是q-1位置(q先固定)的区间(p,q]是不是good。

(1) 如果(p,q]区间不是good,那代表对于某个a,p<=a+1满足了,那为了固定q而让这个条件p<=a+1不满足,我们对p进行自增1的操作,直到(p,q]区间是good为止

(2) 如果(p,q]是good,那我们需要计算q结尾,p到q一共有多少个子序列,这些子序列都是满足good的(不然(p,q]则不满足)。满足区间为[p+1,q],[p+2,q]……[q,q],显然有q-p个是满足的。然后q结尾的区间都计算进去了(因为我们的p是从最小依次增长过来的),接下来计算以q+1结尾的区间。

这么一看,这题的思路就是一个尺取法
时间复杂度O(kn)
AC代码:

#include <bits/stdc++.h>
#define show(x) std::cerr << #x << "=" << x << std::endl;
#define IOS ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
typedef long long ll;
const int MAX = 200500;
#define INF 1e9
const long long MOD = 998244353;
map<ll,bool>vis;
ll aa[MAX];
int main()
{
    IOS;
    int n;
    cin >>n;
    for(int i=1;i<=n;++i){
        cin >> aa[i];
        aa[i]+=aa[i-1];		//记录前缀和数组
    }
    int l=0,r=1;			//表示区间(l,r]
    ll ans=0;
    vis[0]=1;				//如果Sum(l,r]=0 那就不是good区间
    while(r<=n){
        while(vis[aa[r]]){	//(1)部分,前缀和aa[r]访问了第二次
            vis[aa[l]]=0;
            l++;
        }
        vis[aa[r]]=1;		//(2)部分,前缀和aa[r]访问过第一次
        ans+=r-l;			//(2)部分 ,以q为末尾的区间(p,q]有q-p个符合
        r++;
    }
    cout << ans;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值