Codeforces 1333C - Eugene and an array (前綴和)



題意

給定一個長度為 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<<'\n';

    return 0;
}


免責聲明!

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



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