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;
}

 

posted @ 2020-04-09 10:41  Tianwell  阅读(573)  评论(2编辑  收藏  举报