题解:AT_abc371_e [ABC371E] I Hate Sigma Problems

· · 题解

题意

$f(l, r)$ 表示 $a_l \dots a_r$ 中有多少个不同的数。 ## 解法 看到求和计数题,直接有脑容斥: 显然,总共的情况是 $\sum_{i = 1}^{i \leq n} \sum_{i = 1}^{i \leq n - i + 1} i$。 对每个数值讨论: 如果有两个数值重复出现,那么设两个数值出现的位置为 $i, j$,答案会少 $i \times (n - j + 1)$。如果该数值有多个,那么暴力的去想,枚举 $i, j$,是一个 $O(n^2)$ 的。优化的话就是:枚举 $i$,遍历一遍整个数值 `vector` 做个后缀和,统计位置在 $i$ 之后的数 $j$ 的 $\sum n - j + 1$。然后计算就行了,注意可能会重复减掉一个方案,要注意去重。 ```cpp #include <bits/stdc++.h> #define int long long using namespace std; const int N = 2e5 + 5; int n, a[N], ans, dfix[N]; vector<int>cnt[N]; int function1(int x){ // 1 + 2 + ... + x = function1(x) return x + x * x >> 1; } signed main(){ cin >> n; for(int i = 1; i <= n; cin >> a[i++]); for(int i = 1; i <= n; ++i) cnt[a[i]].push_back(i); // 存进 vector for(int i = 1; i <= n; ++i) ans += function1(n - i + 1); // 初始时的答案 for(int i = 1; i <= n; ++i){ dfix[cnt[i].size()] = 0; for(int j = cnt[i].size() - 1; j > -1; --j) dfix[j] = dfix[j + 1] + n - cnt[i][j] + 1; // 处理后缀和 for(int j = 0; j < cnt[i].size(); ++j) ans -= (cnt[i][j] - (j > 0 ? cnt[i][j - 1] : 0)) * dfix[j + 1]; // 减去不合法答案 } cout << ans; return 0; } ```