P1494 [国家集训队]小Z的袜子

(color{#0066ff}{ 题目描述 })

作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……

具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。

你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子。当然,小Z希望这个概率尽量高,所以他可能会询问多个(L,R)以方便自己选择。

然而数据中有L=R的情况,请特判这种情况,输出0/1。

(color{#0066ff}{输入格式})

输入文件第一行包含两个正整数N和M。N为袜子的数量,M为小Z所提的询问的数量。接下来一行包含N个正整数Ci,其中Ci表示第i只袜子的颜色,相同的颜色用相同的数字表示。再接下来M行,每行两个正整数L,R表示一个询问。

(color{#0066ff}{输出格式})

包含M行,对于每个询问在一行中输出分数A/B表示从该询问的区间[L,R]中随机抽出两只袜子颜色相同的概率。若该概率为0则输出0/1,否则输出的A/B必须为最简分数。(详见样例)

(color{#0066ff}{输入样例})

6 4
1 2 3 3 3 2
2 6
1 3
3 5
1 6

(color{#0066ff}{输出样例})

2/5
0/1
1/1
4/15

(color{#0066ff}{数据范围与提示})

30%的数据中 N,M ≤ 5000;

60%的数据中 N,M ≤ 25000;

100%的数据中 N,M ≤ 50000,1 ≤ L < R ≤ N,Ci ≤ N。

(color{#0066ff}{ 题解 })

莫队第一题。。。

莫队的使用有一些限制

首先,问题必须离线

然后,要支持分块

其次,对于区间的转移要很快,一般为(O(1))

这题,显然一个区间的答案为(frac{sum C_{t_i}^2}{C_{len}^2})

其中len为区间长度,(t_i)为颜色为i的袜子在区间中的个数

化简之后变为了(frac{sum t_i*(t_i-1)}{len *(len-1)})

发现分母是固定的,这题又要单独输出分子分母,于是只看分子就行了

显然来了一个数或删掉一个数,我们都可以把当前贡献减掉再加上新的贡献

于是第二个条件满足了, 第一个显然满足,第二个,由于是区间查询,也满足了

那么怎么排序才能保证复杂度呢

我们对于左端点在一个块的,按块的奇偶对r排序,那么r是一个波浪形

如果左端点不在一个块,则按块的编号排序

那么实际上l的移动都是在一个块内,移动完再去下一个块

r的移动是一个波浪,在一个块内单调

那么总复杂度显然是(O(nsqrt n))

#include<bits/stdc++.h>
#define LL long long
LL in() {
	char ch; LL x = 0, f = 1;
	while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
	for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
	return x * f;
}
using std::pair;
using std::make_pair;
const int maxn = 5e4 + 10;
int bel[maxn], n, m, a[maxn];
LL t[maxn];
struct node {
	LL l, r, id;
	friend bool operator < (const node &a, const node &b) {
		if(bel[a.l] == bel[b.l]) return bel[a.l] & 1? a.r < b.r : a.r > b.r;
		return bel[a.l] < bel[b.l];
	}
	LL tot() { return (r - l + 1) * (r - l); }
}e[maxn];
pair<LL, LL> ans[maxn];
LL tot;
LL l = 1, r;
void add(int i) {
	t[i]++;
	if(t[i] >= 2) tot = tot + t[i] * (t[i] - 1) - (t[i] - 1) * (t[i] - 2);
}
void del(int i) {
	t[i]--;
	if(t[i] >= 1) tot = tot + t[i] * (t[i] - 1) - t[i] * (t[i] + 1);
}
LL gcd(LL x, LL y) { return y? gcd(y, x % y) : x; }
void out(const pair<LL, LL> &a) {
	LL x = a.first, y = a.second;
	LL gc = gcd(x, y);
	x /= gc, y /= gc;
	printf("%lld/%lld
", x, y);
}
	
int main() {
	n = in(), m = in();
	int len = sqrt(n);
	for(int i = 1; i <= n; i++) a[i] = in(), bel[i] = (i - 1) / len + 1;
	for(int i = 1; i <= m; i++) e[i].l = in(), e[i].r = in(), e[i].id = i;
	std::sort(e + 1, e + m + 1);
	for(int i = 1; i <= m; i++) {
		while(l > e[i].l) add(a[--l]);
		while(l < e[i].l) del(a[l++]);
		while(r < e[i].r) add(a[++r]);
		while(r > e[i].r) del(a[r--]);
		if(e[i].l == e[i].r) ans[e[i].id] = make_pair(0, 1);
		else ans[e[i].id] = make_pair(tot, e[i].tot());
	}
	for(int i = 1; i <= m; i++) out(ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/olinr/p/10388965.html