首先对于一个 (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] << '
';
return 0;
}