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