C. Good Subarrays(前缀和)

一、问题

在这里插入图片描述

二、分析

这道题目的意思就是给我们一个数组,然后我们从数组中选取一个连续的区间,这个区间满足条件:区间内的元素和等于区间的长度。

对于区间和问题我们先想到的是前缀和的算法。

那么题目中的要求可以表示为: s [ r ] − s [ l − 1 ] = r − ( l − 1 ) s[r]-s[l-1]=r-(l-1) s[r]s[l1]=r(l1)

移向可得:
s [ r ] − r = s [ l − 1 ] − ( l − 1 ) s[r]-r=s[l-1]-(l-1) s[r]r=s[l1](l1)

我们可以构造一个新的数组, d [ i ] = s [ i ] − i d[i] = s[i] -i d[i]=s[i]i

这道题就可以转化为:在 i i i的左侧有多少等于 d [ i ] d[i] d[i]的元素,这个个数就是我们以 i i i为右端点的符合条件的区间数目。

三、代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int a[N], s[N], d[N];
ll ans;
void solve()
{
	ans = 0;
	int n;
	cin >> n;
	string str;
	cin >> str;
	for(int i = 1; i <= n; i ++ )
	{
		a[i] = str[i - 1] - '0';
		s[i] = a[i] + s[i - 1];
		d[i] = s[i] - i;
	}
	unordered_map<ll, ll> cnt;
	for(int i = 0; i <= n; i ++ )
	{
		ans += cnt[d[i]];
		cnt[d[i]] ++;
	}
	cout << ans << endl;
}

int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t --)
	solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值