Description
给定序列 a = ( a 1 , a 2 , ⋯ , a n ) a=(a_1,a_2,\cdots,a_n) a=(a1,a2,⋯,an),有 q q q 次查询,每次查询给定 ( l , r ) (l,r) (l,r).
你需要求出 2 ∑ i ≤ i < j ≤ r [ a i = a j ] ( r − l ) ( r − l + 1 ) \dfrac{2\sum_{i\le i < j \le r} [a_i=a_j]}{(r-l)(r-l+1)} (r−l)(r−l+1)2∑i≤i<j≤r[ai=aj],以最简分数形式输出.
Limitations
1 ≤ n , m ≤ 5 × 1 0 4 1\le n,m\le 5\times 10^4 1≤n,m≤5×104
1 ≤ l ≤ r ≤ n 1\le l\le r\le n 1≤l≤r≤n
1 ≤ a i ≤ n 1\le a_i\le n 1≤ai≤n
0.2 s , 128 MB \textcolor{red}{0.2\text{s}},128\text{MB} 0.2s,128MB
Solution
这种不好直接维护的题,考虑上莫队.
我们设 c n t i cnt_i cnti 为当前区间内 i i i 的出现次数.
那么,这 c n t i cnt_i cnti 个 i i i 可以两两配成满足条件的对,其对分子的贡献显然为 cnt i × ( cnt i − 1 ) \textit{cnt}_i\times(\textit{cnt}_i-1) cnti×(cnti−1).
在 add
和 del
时,先将原来 a x a_x ax 的贡献减掉,更新 cnt \textit{cnt} cnt 后再加回去.
剩下的就是是模板,但有几个坑:
- 分子和分母会爆
int
,要开long long
. - 注意特判 l = r l=r l=r.
- 调块长,实测取 B = n B=\sqrt n B=n 可以过.
Code
2.41 KB , 0.35 s , 2.17 MB (in total, C++20 with O2) 2.41\text{KB},0.35\text{s},2.17\text{MB}\;\texttt{(in total, C++20 with O2)} 2.41KB,0.35s,2.17MB(in total, C++20 with O2)
#include <bits/stdc++.h>
using namespace std;using i64 = long long;
using ui64 = unsigned long long;
using i128 = __int128;
using ui128 = unsigned __int128;
using f4 = float;
using f8 = double;
using f16 = long double;template<class T>
bool chmax(T &a, const T &b){if(a < b){ a = b; return true; }return false;
}template<class T>
bool chmin(T &a, const T &b){if(a > b){ a = b; return true; }return false;
}namespace fastio {} // Removed
using fastio::read;
using fastio::write;struct Query { int l, r, id;inline Query() {}inline Query(int _l, int _r, int _id) : l(_l), r(_r), id(_id) {}
}; signed main() {ios::sync_with_stdio(0);cin.tie(0), cout.tie(0);const int n = read<int>(), m = read<int>();const int B = sqrt(n);vector<int> c(n);for (int i = 0; i < n; i++) c[i] = read<int>(), c[i]--;i64 res = 0;vector<int> cnt(n);auto f = [&](int x) { return 1LL * x * (x - 1) / 2; };auto upd = [&](int x, int k) {res -= f(cnt[c[x]]);cnt[c[x]] += k;res += f(cnt[c[x]]);};vector<Query> qry(m);for (int i = 0, l, r; i < m; i++) {l = read<int>(), r = read<int>(), l--, r--;qry[i] = Query(l, r, i);}sort(qry.begin(), qry.end(), [&](const Query& a, const Query& b) {return (a.l / B == b.l / B) ? (a.r / B < b.r / B) : (a.l / B < b.l / B);});int l = 0, r = -1;vector<i64> num(m), den(m);for (auto& [ql, qr, id] : qry) {while (ql < l) upd(--l, 1);while (r < qr) upd(++r, 1);while (l < ql) upd(l++, -1);while (qr < r) upd(r--, -1);const i64 a = res, b = f(qr - ql + 1), g = gcd(a, b);if (a == 0) num[id] = 0, den[id] = 1;else num[id] = a / g, den[id] = b / g;}for (int i = 0; i < m; i++) {write(num[i]), putchar_unlocked('/');write(den[i]), putchar_unlocked('\n');}return 0;
}