Codeforces 1333C. Eugene and an array(思維) /詳解

Codeforces Round #632 (Div. 2) C. Eugene and an array

題意:
求出一個數列中子區間滿足 此區間的任意子區間之和 不爲0的區間個數。

思路:

  1. 考慮用dp[x]dp[x]記錄前綴和爲xx的區間右端點。
  2. 那麼這道題其實可以看成用map記錄前綴和的路徑,依次計算每個元素作爲區間右端點並且滿足條件時對答案的貢獻,再進行累加即可。
  3. ii是以a[i]a[i]爲右端點的子區間個數,lastlast是 距離 ii最近且[last,i][last,i]中包含和爲0的子段的端點,那麼即說明[last+1,i][last+1,i]不包含和爲0的子區間,所以每次遍歷對答案的貢獻爲ilasti-last
  4. 那麼怎麼求lastlast?
  5. dp[x]dp[x]在前面出現過的時候就說明區間[dp[x]+1,i][dp[x]+1,i]之間的子段和爲0,那麼很明顯,此時last=max(last,dp[x]+1)last=max(last,dp[x]+1)
  6. 這裏取maxmax是防止dp[x]+1dp[x]+1lastlast小,而導致容納了一些錯誤的區間。
  7. 例如[dp[x]+1,i][last,i][dp[x]+1,i]和[last,i]中均包含了子段和爲0的區間,但是如果lastlastdp[x]+1dp[x]+1的話就會把原先的[last,i][last,i]之間的錯誤區間算進答案中,所以上面纔會提及lastlast是 距離 ii 最近的一點。
  8. 但是不僅僅是如此,還要注意初始化 : dp[0]=last=0dp[0]=last=0,其他應該沒什麼問題和坑點了。
  9. 如果覺得有幫助的話給個贊,謝謝!
  10. 或者有什麼講的不清楚的歡迎留言私信交流~

代碼:

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) (x&(-x))
using namespace std;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();return s*w;}
void put1(){ puts("YES") ;}void put2(){ puts("NO") ;}void put3(){ puts("-1"); }
ll qp(ll a,ll b, ll p){ll ans = 1;while(b){if(b&1){ans = (ans*a)%p;--b;}a =
(a*a)%p;b >>= 1;}return ans%p;}
const ull base=2333; const ull pp=19260811; const ull ppp=999998639;
 
const int manx=1e5+5;
const int mo=998244353;
 
ll s[manx];
map<ll,ll>dp;
 
int main(){
    ll n=read();
    ll ans=0,s=0,last=0; dp[s]=0;
    for(int i=1;i<=n;i++){
        ll x=read();
        s+=x;
        if(dp.count(s)) last=max(last,dp[s]+1);
        dp[s]=i;
        ans+=i-last;
     //   cout<<ans<<" "<<last<<endl;
    }
    cout<<ans;
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章