传送门
分析
有点可惜,这道题原本可以A掉的,但是比赛的时候开的int答案溢出了
填空题:不开____见祖宗
这道题我一开始的思路是尺取加前缀和,被T掉了,后来观察这个数据范围大概知道这是个O(n)的做法
首先我们需要将每一位上数字-1,这样就可以把这个问题转换为求区间和为0的问题了
我们需要维护一个前缀和,当我们计算到第i位的时候,假设前缀和为x,如果x为0的话,答案可以+1,并且如果前面有一段前缀和为0的话,减去这一段也可以做到区间和为0,所以加上前面前缀和为0出现的次数
如果前缀和不为0,那么我们只需要减去一段区间和为x的区间就可以了
所以我们只需要维护一下第i位前面的前缀和,用map存一下就可以了
最后记得注意一下答案范围就好了
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <cstring>
#include <unordered_map>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC option("arch=native","tune=native","no-zero-upper")
#pragma GCC target("avx2")
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
int T;
typedef pair<int,ll> PII;
const int INF = 0x3f3f3f3f;
const int N = 5e4 + 10;
int main(){
scanf("%d",&T);
while(T--){
unordered_map<int,int> M;
int n;
scanf("%d",&n);
string str;
cin >> str;
ll ans = 0;
int sum = 0;
int x;
for(int i = 1;i <= n;i++){
x = str[i - 1] - '0' - 1;
sum += x;
if(sum == 0) ans++;
ans += M[sum];
M[sum]++;
}
printf("%lld\n",ans);
}
}