Good Subarrays

Good Subarrays

原题链接:传送门

题目大意

给定一个序列,让你尝试求出序列中,存在多少子数组的区间和等于子数组的长度

\(\sum_{i = l}^r ai = r - l + 1\)

分析

对于这个问题,如果我们采用暴力做法的话时间复杂度在\(O(n^2)\) ,是一定会超时的。那么我们尝试对问题的公式做一下等价变形。

\(\begin{equation} \begin{aligned} \sum_{i = l}^r ai &= r - l + 1\\ \sum_{i = l}^r(ai - 1)&= (r - l + 1) - (r - l + 1) \\ \sum_{i = l}^r(ai - 1)&=0 \end{aligned} \end{equation}\)

我们让两边都减去区间长度发现左边变成了区间[l , r] 中元素值 - 1 的区间和

我们需要求出来这样的前缀和区间中有多少个等于0的即可。

此时我们可以借助前缀和思想来简化这个问题

对于样例 : 1 1 0 1 1

1 2 3 4 5
原数组 a 1 1 0 1 1
原数组位置-1 :b 0 0 -1 0 0
数组b的前缀和 0 0 -1 -1 -1

注意事项

  • 我们发现对于位置 i ,如果当前位置前缀和等于0说明其自身可以构成一个区间那么更新答案ans = ans + 1

  • 如果当前元素的值已经出现过那么当前位置 i 且前缀和为 s 那么其一定可以和其在 i 前面的等于当前元素的区间且和为 s 重新进行区间组合变成新的区间,故此时 ans += 原来区间的个数,且当前区间值等于 s 的区间个数++

总结

  • 出现子数组这类问题,大部分都可以优先想到使用前缀和进行辅助处理,因为子数组是数组中的一个部分,该段的和其实就可以利用前缀和进行求解。并且迁回和更新具有线性递增当前和只由前面的元素所决定。

AC 代码

C++ code

void slove()
{
	int n;cin >> n;
	string s;cin >> s;
	s = '0' + s;
	map<int,int> m;
	ll ans = 0;int sum = 0;
	for(int i = 1;i < s.size();i ++)
	{ 
		int x = s[i] - '0' - 1;
		sum += x;
		if(sum == 0)
		{
			ans++;
		}
		ans += m[sum];
		m[sum] ++;
	}
	cout << ans << endl;
}
posted @ 2020-09-01 21:38  _starsky  阅读(153)  评论(0编辑  收藏  举报