zoukankan      html  css  js  c++  java
  • Codeforces 1333C


    题意

    给定一个长度为 n 的数组 ar (n<=2e5)

    问这个数组 ar 中有多少子数组是好数组

    子数组的定义为:

      把一个数组前面删去0个或全部元素,后面删去0个或全部元素得到的数组就是原数组的子数组

    好数组的定义为:

      对于数组 a 的每个子数组 b 都满足 sum{b} ≠ 0

      则数组 a 就是个好数组

    每个数组元素保证 abs(a[i])<=1e9




    解题思路

    假设我们找到了一个和为0的子数组 br

    那么只要有其他子数组包含br,那么这些子数组都不能称作好数组


    所以我们在处理某个元素ar[i]时,只看以ar[i]为右边界的子数组,r=i

    从 i 位置开始往左寻找,直到将某个和为0的子数组包含进来后停止,令此时左边界为 l

    那么 r-l 就是以ar[i]为右边界好数组的个数(包含[r,r]、不包含[l,r])

    所以只要记录下 1 到 i 这段区间中,和为0的子数组的最大左边界maxL即可

    每次答案加上 i-maxL


    那么对于和为0的子数组的判断,记录前缀和是否出现过进行判断

    比如[1,x]的和为a,[1,y]的和也为a,那就说明[x+1,y]这段子数组和为0

    因为前缀和分布离散,所以使用map/unordered_map进行储存


    总体时间复杂度为O(nlogn)




    程序

    map中未出现的key的value默认为0,可以用来判断某个前缀和是否出现过

    注意刚开始一个元素都没有的时候也要记录下前缀和为0,否则第一个从1开始和为0的子数组将无法进行判断

    因为有可能出现两个和为0的子数组呈包含关系(例如1 1 -1 -1,[1,4]和[2,3]和为0),这种情况下如果不对maxL进行取大,可能原本maxL为2,在执行到 i=4 时被小值取代变成maxL=1,与想法不符

    最后,注意长整型

    (186ms/1500ms)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    map<ll,int> mp;
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        int n;
        ll ar,sum=0,ans=0,maxL=1;
        cin>>n;
        mp[0]=1;//初始前缀和为0
        for(int i=2;i<=n+1;i++)
        {
            cin>>ar;
            sum+=ar;
            if(mp[sum]!=0)
                maxL=max(maxL,ll(mp[sum]+1)); //记得取大(否则wa8……)
            ans+=i-maxL;//以i为右边界,满足题意的个数
            mp[sum]=i;
        }
        cout<<ans<<'
    ';
    
        return 0;
    }
    

  • 相关阅读:
    30分钟带你了解Docker
    30分钟了解Springboot整合Shiro
    vuejs 和 element 搭建的一个后台管理界面
    MySQL缓存参数优化(转)
    MVC+EF(CODEFIRST)+EASYUI医药MIS系统
    博客园开通打赏功能以及HTTPS打赏失效的探究 -玩转打赏功能
    SpringMVC集成rabbitmq:优化秒杀下单环节
    国内最火5款Java微服务开源项目
    SpringCloud系列——SSO 单点登录
    玩转spring boot
  • 原文地址:https://www.cnblogs.com/stelayuri/p/12664224.html
Copyright © 2011-2022 走看看