题目大意
平均数
给定长度为 \(n\) 的非负整数序列 \(a_1,a_2,\cdots,a_n\),问有多少个区间 \([l,r](1\le l\le r\le n)\) 满足 \(a_l,a_{l+1},\cdots,a_{r}\) 的平均数为给定非负整数 \(k\)。
思路
发现直接维护平均值很难维护,于是就有了一个平均数非常经典小trick,不是直接维护一个区间的平均值,而是现将每一个数都减去 \(k\),如果有一个区间和加起来为零,就说明这个区间的平均值为 \(k\)。
举个栗子:
$\{1\ 3\ 5\} $,假设 \(k = 3\),则将每个元素减 \(k\),得到 \(-2\ 0\ 2\),发现 \([1, 3]\) 这段区间的和为 \(0\),所以 \([1, 3]\) 这段区间的平均值就为 \(3\)。
有了这个技巧,就可以做这题了。首先先将所有元素减去 \(k\),由于要求有多少个区间的平均值为 \(k\),所以需要用到前缀和,问题就转化成了有多少个区间 \(s[r] - s[l-1] = 0\)。
枚举右端点,要求有多少个左端点 \(l\) 满足 \(s[r] - s[l-1] = 0\),移项一下就是求有多少个左端点满足 \(s[l] = s[r]\),用 \(map\) 维护再 \(r\) 之前有多少 \(s\) 为 \(s[r]\) 即可。
代码
#include <bits/stdc++.h>
using namespace std;const long long N = 100010;
long long n, k;
map<long long, long long> box;
map<long long, bool> ;int main() {ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin >> n >> k;long long s = 0, ans = 0; box[0]++;for (long long i = 1; i <= n; i++) {long long a; cin >> a;s += a - k;ans += box[s];box[s]++;}cout << ans << endl;return 0;
}