• CF#632 C.Eugene and an array


       说实话这种区间计数问题自己又大脑短路了,以后再也不能犯这种问题了(TAT)

    原题连接http://codeforces.com/contest/1333/problem/C

    题意:求判定为“good”的子区间个数。good : 在该区间内的所有子区间,不存在和为0的子区间。子序列:对原序列首位依次删除任意个形成的序列

    思路:从对 “所有子区间” 的统计符合条件个数可以看出,这是一道标准的区间计数问题。而对于区间计数的方式由于是对所有区间的统计,所以一定会用到 贡献的思想。

    思考1:如何覆盖所有区间通过 for 循环

    方案一:以 i 为起点 j 为终点,二维数组来表示区间状态 (一些dp的表现方式 , 或者以 i为起点,j为当前位置向后长度)

     方案二:以 i 为起点 j 为向前长度的位置 , 如下图所示的覆盖方式 (Codeforces Round #585 (Div. 2) B. The Number of Products :也是用的同样的方法

     

     

    而这样的方法有一个好处,就是 通过前缀和 map 来判断 在 map[a[i]] ~ i 这个区间范围的和为0 . 同时这一方法在 统计所有异或值为0的子区间,也是用同样的方法。

    还是今年牛客寒假里面的一道题,自己 AC 过(TAT), 所以通过map维护一个前缀和为 x 的最后位置,以 i 为右端点, 则在区间 map[a[i]]+1 ~ i 这里必定没有非零子区间(前提是没有0包含)

    所以嗯,对应的 code 就这样出来了: 这里由于 下标的问题,我把原数组下标全部向右移动了一格

    #include<bits/stdc++.h>
    #define IOS ios::sync_with_stdio(0); cin.tie(0);
    typedef long long ll;
    using namespace std;
    const int maxn = 1e6+5;
    ll a[maxn];
    map<ll,ll>mp;
    int main(){
        IOS
        int n;
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        for(int i=2;i<=n;i++) a[i] += a[i-1]; // 前缀和
        for(int i=n+1;i>=2;i--) a[i] = a[i-1];  
        a[1] = 0;
        ll ans = 0,p = 1;
        ll i;
        mp.clear();
        mp[0] = 1;
        for(i=2;i<=n+1;i++){
            if(mp[a[i]]) p = max(p,mp[a[i]]+1);
            mp[a[i]] = i;
            if(a[i]-a[i-1] == 0) {
                p = i; continue;
            }        
            ans += i - p; //非零区间个数
        }
        cout<<ans<<endl;
    }
  • 相关阅读:
    MongoDB 常用命令
    jpa一对多
    jpa的常用注解
    jpa常用方法
    springdata查询的多种用法
    springdata笔记
    java 动态代理 demo 实现原理 参数理解(三)
    Solr
    一些重要的知识点-数据库优化-angularjs--JSON-fastDFS
    支付功能
  • 原文地址:https://www.cnblogs.com/Tianwell/p/12665218.html
Copyright © 2020-2023  润新知