周赛361 leetcode2845. 统计趣味子数组的数目

题解

对于子数组[l, r],如何表示cnt。如果把模m等于k的元素记为1,不为k的记为0,那么cnt就是[l,r]的元素之和。首先要知道怎么算,比如对于数组[3,1,9,6],m=3,k=0,这个数组可以记为[1,0,1,1],那么对于整个数组,(1+0+1+1)%3=0,就是一个趣味数组,对于第二元素单独作为子数组,0%3=0,也是一个趣味数组,所以答案是2。
看数据范围n是1e5,如果暴力枚举子数组,至少是平方复杂度,所以不行。处理子数组的元素和,经典的技巧就是前缀和。前缀和有个细节就是前面补个0,为了方便数组前缀和。

cnt = x[L] + ... + x[R] = S[R+1] - S[L]
(S[R+1] - S[L]) % m = k
不需要补m:S[R+1] % m - S[L] % m = k
S[R+1] % m - k = S[L] % m
需要补m:S[R+1] % m - S[L] % m + m = k
S[R+1] % m - k + m = S[L] % m
所以不需要补m和需要补m可以归纳为:(S[R+1] % m - k + m) % m = S[L] % m
枚举R,用哈希表统计有多少个S[L] % m,也就等价于统计(S[R+1] % m - k + m) % m的个数,然后加到ans里,并更新当前的哈希表
可以边算前缀和边遍历,所以就用一个变量pre记录前缀和就可以,不需要额外用数组存

class Solution {
public:
    long long countInterestingSubarrays(vector<int>& nums, int modulo, int k) {
        int a[100010];
        unordered_map<int, int> mp;
        mp[0] = 1;
        long long ans = 0;
        int pre = 0;
        for(int x : nums)
        {
            pre += x % modulo == k;
            ans += mp[(pre-k+modulo) % modulo];
            mp[pre%modulo]++;
        }
        return ans;
    }
};
posted @ 2023-10-15 18:33  .Ivorelectra  阅读(8)  评论(0编辑  收藏  举报