C. Good Subarrays(老套路思维了)

吐槽一句:这种题型遇到过好多次

几乎每一次都是枚举区间开头位置计算结果


考虑现在区间是[l,r],考虑加入a[r+1]对这个区间合法性的影响

区 间 长 度 每 增 加 1 就 需 要 一 个 0 进 来 抵 消 区间长度每增加1就需要一个0进来抵消 10

当 数 字 为 1 时 , 加 不 加 这 个 1 无 所 谓 , 加 入 这 个 1 , 区 间 长 度 加 1 , 值 也 加 1 当数字为1时,加不加这个1无所谓,加入这个1,区间长度加1,值也加1 1,1,1,1,1

当 数 字 为 2 时 , 如 果 加 入 这 个 2 , 区 间 长 度 加 1 , 值 加 2 , 此 时 需 要 有 0 来 填 充 当数字为2时,如果加入这个2,区间长度加1,值加2,此时需要有0来填充 2,2,1,2,0

我 们 把 0 看 作 − 1 , 表 示 加 入 0 对 区 间 的 影 响 是 负 面 的 我们把0看作-1,表示加入0对区间的影响是负面的 01,0

同 理 把 1 看 作 0 , 表 示 加 入 1 对 区 间 是 没 影 响 的 同理把1看作0,表示加入1对区间是没影响的 10,1

把 数 字 x 看 作 x − 1 , 表 示 加 入 数 字 x 需 要 区 间 内 还 有 x − 1 个 0 才 能 抵 消 把数字x看作x-1,表示加入数字x需要区间内还有x-1个0才能抵消 xx1,xx10

此时我们要找的合法区间,就是区间和为0的区间了

剩 下 的 就 简 单 了 , 先 用 m a p 记 录 一 遍 所 有 前 缀 和 剩下的就简单了,先用map记录一遍所有前缀和 ,map

比 如 , 令 当 前 位 置 的 前 缀 和 是 x , 就 m a p [ x ] + + 比如,令当前位置的前缀和是x,就map[x]++ ,x,map[x]++

接 下 来 枚 举 每 个 位 置 作 为 开 头 , 由 于 区 间 结 尾 大 于 开 头 接下来枚举每个位置作为开头,由于区间结尾大于开头 ,

所 以 计 算 答 案 时 先 m a p [ x ] − − , 因 为 这 个 位 置 之 前 的 前 缀 和 不 能 使 用 ( 区 间 末 尾 > 开 头 ) 所以计算答案时先map[x]--,因为这个位置之前的前缀和不能使用(区间末尾>开头) map[x],使(>)

然 后 答 案 加 上 m a p [ x ] , 这 个 m a p [ x ] 表 示 后 面 的 前 缀 和 是 x 的 次 数 然后答案加上map[x],这个map[x]表示后面的前缀和是x的次数 map[x],map[x]x

这 就 是 区 间 和 为 0 的 个 数 这就是区间和为0的个数 0

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
int t,n,sumn[maxn],top;
char a[maxn];
map<int,int>mp;
int main()
{
	cin >> t;
	while( t-- )
	{
		mp.clear();
		long long ans=0;
		scanf("%d%s",&n,a+1);
		int qian=0;
		for(int i=1;i<=n;i++)
		{
			int w=a[i]-'0'-1;
			qian+=w;
			mp[qian]++;
		}
		qian=0;
		ans=mp[0];//前缀和本来就是0的也可以作为答案,可以看作区间开头是0 
		for(int i=1;i<=n;i++)
		{
			int w=a[i]-'0'-1;
			qian+=w;
			mp[qian]--;//先把[1,i]的前缀和消除掉,我们想要的区间结尾要大于i才行 
			ans+=mp[qian];	
		}
		cout << ans << "\n";
	}
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值