CF 1398C

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]==rl 由此可得: 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;
}

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/108410519