Codeforces C. Good Subarrays

题意: 给定好子数组的概念:若子数组的元素之和等于元素个数,那么这个子数组就为好子数组。那么给你一个数组序列字符串,判断该序列有多少个好子数组。

题解:首先子数组元素之和等于元素个数,这就意味着我们令每一个子数组元素减去1,就可以等价为子数组元素和为0的数组即为好子数组(思维精髓)。那么我们维护一个前缀和,如果当前前缀和为0,那么答案加一,同时我们记录在它之前前缀和同样为0的个数,那么这个前缀和减去前面这些前缀和为0的区间依然是前缀和为0的区间,则这些子数组也符合题意,则答案再加前面已有前缀和为0的子数组的个数。若当前前缀和不为0,为x,则同样记录在这之前前缀和同样为x的个数,那么这个前缀和减去前面那些前缀和为x的区间,剩下的区间是为0的区间。

代码如下:(注释及其详细)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
	int T;
    scanf("%d",&T);
    while(T--)
	{
        map<int,int> M; //M[i] 表示当前前缀和为i的个数 
        int n;
        scanf("%d",&n);
        string str;
        cin>>str;
        ll ans=0;
        int sum=0;
        int x;
        for(int i=0;i<n;i++)
		{
            x=str[i]-'0'-1;
            sum+=x;
            if(sum==0) //当前前缀和为0,则总数++ 
				ans++;
            ans+=M[sum]; //找到在当前i之前的前缀和为sum的个数加上 若当前sum=0(比如a[1]+a[2]+a[3]) 那么若之前的前缀和也出现了0(比如a[1]),那么a[2]+a[3]必为0,须加上
						 //同理若a[1]+a[2]=0 则a[3]必为0 ,因此前面的前缀和有多少个与当前前缀和相同的,总数就加几   
						 //若当前sum不为0的话,例如为a[1]+a[2]+a[3]=5,则在当前i之前的前缀和 若也出现为5 比如 a[1]+a[2]=5,则就必有a[3]=0,是我们所要的,加上  
            M[sum]++;
        }
        printf("%lld\n",ans);
    }
    
}

猜你喜欢

转载自blog.csdn.net/henulmh/article/details/108020592
今日推荐