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