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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM