洛谷P1494 小Z的袜子 莫队

首先对于一个 \(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;
}
posted @ 2020-07-17 11:29  wljss  阅读(147)  评论(1编辑  收藏  举报