C. Eugene and an array
题目链接-C. Eugene and an array
题目大意
数组内和不为
的连续子序列被称为好的序列,统计数组
中有几个好的序列
解题思路
- 求出前缀和,前缀和 意味着 这一段的和为
map
维护当前出现过的前缀和的下标,即用map
记录 上一次出现的位置,即左端点- 用 来记录当前没有前缀和为 的区间的左端点(左端点最大值),以当前点 为右端点,因为区间为左开右闭,所以 要初始化为
- 所以满足条件的区间就是 ,然后区间内数的个数就是增加当前这个点后增加的好序列个数,即不包含子串和为 的个数为 ,累加即可
- 具体操作见代码
附上代码
#pragma GCC optimize("-Ofast","-funroll-all-loops")
//#pragma GCC diagnostic error "-std=c++11"
#include<bits/stdc++.h>
#define int long long
#define lowbit(x) (x &(-x))
#define endl '\n'
using namespace std;
const int INF=0x3f3f3f3f;
const int dir[4][2]={-1,0,1,0,0,-1,0,1};
const double PI=acos(-1.0);
const double e=exp(1.0);
const double eps=1e-10;
const int M=1e9+7;
const int N=1e5+10;
typedef long long ll;
typedef pair<int,int> PII;
typedef unsigned long long ull;
map<int,int> mp;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
mp[0]=0;//第一个数前面前缀和为0
int n,ans=0,tmp=0,k=-1;
cin>>n;
for(int i=1;i<=n;i++){
int t;
cin>>t;
tmp+=t;//记录前缀和
if(mp.count(tmp))//判断tmp是否出现过
//因为初始化mp[0]=0,所以用if(mp[tmp])判断会出错
k=max(k,mp[tmp]);
ans+=i-k-1;//注意边界问题
mp[tmp]=i;
}
cout<<ans<<endl;
return 0;
}