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

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

标签

  • 基础莫队

前言

简明题意

  • 查询区间[L,R]选出两个相等的数的概率

思路

  • 莫队很好打,这题难点在于指针移动后概率如何更新。
  • 令cnt[]为当前区间每个数出现的次数,l,r表示当前区间的端点,于是这个区间的答案就应该是:

\[\frac{\sum\limits_{x(cnt[x>=2])} C_{cnt[x]}^{2}}{C_{r-l+1}^{2}} \]

  • (下面省略cnt[x]>=2)把组合数拆开:

\[\frac{\sum\limits_{x}( cnt[x](cnt[x]-1)}{(r-l+1)(r-l)} \]

  • 发现分子比较好处理,先减掉cnt[x]原先的贡献,再加上新的贡献就可以了,现在问题在于分母的处理。

\[(r-l+1)(r-l) \]

  • 其实也很好处理鸭。把r-l看成一个整体,然后就很简单了。然后我们应该多开一个变量维护r-l的值,就可以了

注意事项

  • longlong

总结

  • 初始时l=1,r=0,那么初始时的r-l应该是-1

AC代码

#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;

const int maxn = 5e4 + 10;

long long gcd(long long a, long long b)
{
	if (b == 0) return a;
	return gcd(b, a % b);
}

struct Query
{
	int l, r, id, k;
	bool operator <(const Query& a)const
	{
		if (k == a.k)
			return r < a.r;
		return k < a.k;
	}
};

Query query[maxn];
int n, q, a[maxn];

long long cnt[maxn];
long long mu = 0, zi = 0, r_l = -1;
void add(int x)
{
	x = a[x];
	mu += 2 * r_l + 2, r_l++;
	zi -= cnt[x] * cnt[x] - cnt[x];
	cnt[x]++;
	zi += cnt[x] * cnt[x] - cnt[x];
}
void remove(int x)
{
	x = a[x];
	mu -= 2 * r_l, r_l--;
	zi -= cnt[x] * cnt[x] - cnt[x];
	cnt[x]--;
	zi += cnt[x] * cnt[x] - cnt[x];
}

pair<long long, long long> ans0[maxn];
void solve()
{
	scanf("%d%d", &n, &q);
	int len = sqrt(n / 2 * 3);
	for (int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	for (int i = 1; i <= q; i++)
		scanf("%d%d", &query[i].l, &query[i].r), query[i].id = i, query[i].k = (query[i].l - 1) / len + 1;
	sort(query + 1, query + 1 + q);

	int l = 1, r = 0;
	for (int i = 1; i <= q; i++)
	{
		int L = query[i].l, R = query[i].r, id = query[i].id;
		while (l < L) remove(l++);
		while (l > L) add(--l);
		while (r < R) add(++r);
		while (r > R) remove(r--);

		if (zi == 0 || L == R) ans0[id].first = 0, ans0[id].second = 1;
		else
		{
			long long t = gcd(zi, mu);
			ans0[id].first = zi / t, ans0[id].second = mu / t;
		}
	}

	for (int i = 1; i <= q; i++)
		printf("%lld/%lld\n", ans0[i].first, ans0[i].second);
}

int main()
{
	freopen("Testin.txt", "r", stdin);
	solve();
	return 0;
}
posted @ 2019-08-07 14:38  danzh  阅读(120)  评论(0编辑  收藏  举报