首先对于一个 \(l\) ~ \(r\) 的区间,设 \(m=r-l+1\) ,我们知道总的小选区袜子的方案数是\(\displaystyle C_m^2=\frac{m(m-1)}{2}\)
设袜子一共有 \(k\) 种颜色,在 \(l\) ~ \(r\) 第 \(i\) 种颜色一共有 \(cnt[i]\) 种,那么 \(l\) ~ \(r\) 里选出相同颜色人的袜子的方案数是 \(\displaystyle \sum_{i=1}^{k}C_{cnt[i]}^{2} = \sum_{i=1}^{k} \frac{cnt[i](cnt[i]-1)}{2}\),概率就是\(\displaystyle \frac{\sum_{i=1}^{k}\frac{cnt[i](cnt[i]-1)}{2}}{\frac{m(m-1)}{2}}\)
我们还知道 \(\displaystyle \frac{m(m-1)}{2}=\sum_{i=1}^{m-1}i\),所以分子和分母就可以分别用莫队来计算了。
退役人表示不想写代码并丢出了学弟的代码
#include <bits/stdc++.h>
#define N 500009
using namespace std;
int n, m, col[N], ans[N][3], cnt[N];
int fz, fm, block, len;
struct Node
{
int l, r;
int ord;
}e[N];
inline int cmp (Node x, Node y)
{
if (x.l/block == y.l/block) return x.r < y.r;
return x.l < y.l;
}
inline void add (int x)
{
fz += cnt[x], ++ cnt[x];
fm += len, ++ len;
}
inline void del (int x)
{
-- cnt[x], fz -= cnt[x];
-- len, fm -= len;
}
inline int gcd (int x, int y) {return !y ? x : gcd(y, x%y);}
int main ()
{
int l(1), r(0);
scanf ("%d%d", &n, &m);
block = n/sqrt(m);
for ( int i = 1;i<=n;++i) scanf ("%d", &col[i]);
for ( int i = 1;i<=m;++i) scanf ("%d%d", &e[i].l, &e[i].r), e[i].ord = i;
sort (e+1, e+n+1, cmp);
for ( int i = 1;i<=m;++i)
{
if (e[i].l == e[i].r)
{
ans[e[i].ord][0] = 0;
ans[e[i].ord][1] = 1;
continue;
}
while (l > e[i].l) add (col[--l]);
while (r > e[i].r) del (col[r--]);
while (l < e[i].l) del (col[l++]);
while (r < e[i].r) add (col[++r]);
int g = gcd(fz, fm);
ans[e[i].ord][0] = fz/g;
ans[e[i].ord][1] = fm/g;
}
for ( int i = 1;i<=m;++i) cout << ans[i][0] << '/' << ans[i][1] << '\n';
return 0;
}