C. Eugene and an array (区间为0前缀和处理)

题目

思路:以每一个位置作为右端点取其前面为0区间的左端点的最大值为左端点,这一个字串就是以该位置为右端点,满足条件的最大长度的子串,它产生的贡献是(r-lmax-1,为了不把左端包含进去,包含进去就有为0的区间了),所有贡献相加即为答案。

而对于如何判断一个区间是否为0,以及这个最大左端点的记录。我们可以使用前缀和来纪录某区间是否为0,sum[i]=sum[j] 那从i+1…j的元素的和为0,我们用map来记录,每次添加进一个新的和,如果前面已经出现了该值,则代表从前一个位置+1到此区间和为0,然后对于取得最大左区间位置,也用map来记录,得到一个新值k时,用map[k]=其位置i,就顺便记录了位置的左段-1处,因为是从i+1…r才是和为0的区间,i+1才是左端,相应贡献为r-max(lmax,i+1)-1。

Code:

#include<iostream>
#include<map>
#include<cmath>
#include<set>
#define FAST ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
typedef long long ll;
const int Max = 1e6 + 5;
int lst[Max];
map<ll, ll> ma;


int main()
{
    
    
	int n;cin >> n;
	for (int i = 1;i <= n;i++)cin >> lst[i];
	ll sum = 0;ma[0] = 0;
	ll ll = -1, ans = 0;
	for (int i = 1;i <= n;i++)
	{
    
    
		sum += lst[i];
		if (ma[sum]||sum==0)
		{
    
    
			ll = max(ll, ma[sum]);
		}
		ans += i - ll - 1;
		ma[sum] = i;
	}
	cout << ans;
}

猜你喜欢

转载自blog.csdn.net/asbbv/article/details/114811789