說實話這種區間計數問題自己又大腦短路了,以后再也不能犯這種問題了(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; }