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;
}