C - Good Subarrays
题意:给一个长度在1e5之内的大数,把大数的每一位看成一个10以内的个位数,问区间和等于区间长度的区间个数有多少个?
思路:定义 prefix[x] 表示区间 [1, x) 的前缀和。对于区间[l, r),满足题意则有
p
r
e
f
i
x
[
r
]
−
p
r
e
f
i
x
[
l
]
=
=
r
−
l
prefix[r] - prefix[l] == r - l
prefix[r]−prefix[l]==r−l 由此可得:
p
r
e
f
i
x
[
r
]
−
r
=
=
p
r
e
f
i
x
[
l
]
−
l
prefix[r] - r == prefix[l] - l
prefix[r]−r==prefix[l]−l。所以我们求出
i
[
1
,
n
+
1
]
i [1, n + 1]
i[1,n+1]的
p
r
e
f
i
x
[
i
]
−
i
prefix[i] - i
prefix[i]−i,然后将所有的结果求C(num, 2),最后相加即可。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#define INF 0x3f3f3f3f3f3f
using namespace std;
typedef long long ll ;
const ll mod = 1e8 + 7;
const int maxN = 1000006;
int read(){
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') f = -f; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
ll getCn2(ll n) {
return n * (n - 1) / 2;
}
int n, prefix[maxN]; //prefix[i]: [1, i)的前缀和
map<int, int>mp;
int main() {
int t; cin >> t;
while(t -- ) {
map<int, int>().swap(mp);
n = read();
string s; cin >> s;
mp[-1] ++ ;
for(int i = 2; i <= n + 1; ++ i ) {
prefix[i] = prefix[i - 1] + s[i - 1 - 1] - '0';
mp[prefix[i] - i] ++ ;
}
ll ans = 0;
map<int, int>::iterator it;
it = mp.begin();
while(it != mp.end()) {
ans += getCn2((ll)it->second);
++ it;
}
cout << ans << endl;
}
return 0;
}