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;
}