题目链接
题意:求区间内任取两点,颜色相同的概率。
题解:对于一个
[
l
,
r
]
[l, r]
[l,r]的区间,我们设一个
n
u
m
num
num数组,
n
u
m
[
i
]
num[i]
num[i]代表当前区间第
i
i
i个颜色的数量,那么我们最终需要求出的答案即为
∑
i
=
1
n
n
u
m
[
i
]
∗
(
n
u
m
[
i
]
−
1
)
C
r
−
l
+
1
2
\frac{\sum_{i = 1 }^n num[i]*(num[i]-1)}{C_{r - l + 1}^{2}}
Cr−l+12∑i=1nnum[i]∗(num[i]−1)
然后就用莫队板子去维护一下
a
n
s
ans
ans就好了。
#include <bits/stdc++.h>
using namespace std;
template <class T> inline void read(T &x) {
int f = 0;x = 0;char ch = getchar();
for (; !isdigit(ch); ch = getchar()) f |= (ch == '-');
for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
if (f) x = -x;
}
typedef long long ll;
const int maxn = 5e4 + 7;
int gcd(int a, int b) {
return a == 0? b : gcd(b % a, a);
}
int n, m, cor[maxn], top[maxn], di[maxn], num[maxn];
int pos[maxn];
struct Node{
int l, r, id;
}node[maxn];
bool cmp(Node a, Node b) {
if (pos[a.l]==pos[b.l]){
if (pos[a.l]&1) return a.r<b.r;
else return a.r>b.r;
}
else return pos[a.l]<pos[b.l];
// if (pos[a.l] == pos[b.l]) return a.r < b.r;
// return a.l < b.l;
}
void add(int j, int &ans) {
ans -= (ll)num[cor[j]] * (ll)(num[cor[j]] - 1) / 2;
num[cor[j]]++;
ans += (ll)num[cor[j]] * (ll)(num[cor[j]] - 1) / 2;
}
void del(int j, int &ans) {
ans -= (ll)num[cor[j]] * (ll)(num[cor[j]] - 1) / 2;
num[cor[j]]--;
ans += (ll)num[cor[j]] * (ll)(num[cor[j]] - 1) / 2;
}
void solve() {
int pre = -1, ans = 0, pl = 1, pr = 0;
for (int i = 1; i <= m; ++i) {
int l = node[i].l, r = node[i]. r, id = node[i].id;
//原本每次到新区间都重新计算一次,后来发现按奇偶排序,一直移快一点
// if (pos[l] != pre) {
// pre = pos[l];
// ans = 0;
// pl = l, pr = r;
// memset(num, 0, sizeof(num));
// for (int j = l; j <= r; ++j) {
// ans -= (ll)num[cor[j]] * (ll)(num[cor[j]] - 1) / 2;
// num[cor[j]]++;
// ans += (ll)num[cor[j]] * (ll)(num[cor[j]] - 1) / 2;
// }
// int tmp = (ll)(r - l + 1) * (ll)(r - l) / 2;
// if (tmp == 0) {
// top[id] = 0, di[id] = 1;
// continue;
// }
// int g = gcd(ans, tmp);
// top[id] = ans / g, di[id] = tmp / g;
// }
// else {
//注意自加自减的顺序
while (l > pl) del(pl++, ans);
while (l < pl) add(--pl, ans);
while (r > pr) add(++pr, ans);
while (r < pr) del(pr--, ans);
int tmp = (ll)(r - l + 1) * (ll)(r - l) / 2;
//题目提醒了l==r的情况,但下面的数据范围却没有,不特判会除0
if (tmp == 0) {
top[id] = 0, di[id] = 1;
continue;
}
int g = gcd(ans, tmp);
top[id] = ans / g, di[id] = tmp / g;
// }
}
}
int main() {
read(n), read(m);
for (int i = 1; i <= n; ++i) read(cor[i]);
int len = sqrt(n);
for (int i = 1; i <= n; ++i) pos[i] = (i + len - 1) / len;
for (int i = 1; i <= m; ++i) {
read(node[i].l), read(node[i].r);
node[i].id = i;
}
sort(node + 1, node + 1 + m, cmp);
solve();
for (int i = 1; i <= m; ++i) {
printf("%d/%d\n", top[i], di[i]);
}
return 0;
}