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

题目大意:

小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。
问有多大的概率在 [ L , R ] [L,R] [L,R]间抽到两只颜色相同的袜子。
会有m个询问。
有L=R的情况,请特判这种情况,输出0/1。
在这里插入图片描述

分析:

对于区间 [ x , y ] [x,y] [x,y],不同的袜子有 z z z中,每种有 a i ai ai只,
那么答案就是 ∑ ( a i ∗ ( a i − 1 ) / 2 ) ( y − x + 1 ) ( y − x ) / 2 \frac{\sum(ai*(ai-1)/2)}{(y-x+1)(y-x)/2} (yx+1)(yx)/2(ai(ai1)/2)
化简即为 ∑ a i 2 − ( y − x + 1 ) ( y − x + 1 ) ( y − x ) \frac{\sum a_i^2-(y-x+1)}{(y-x+1)(y-x)} (yx+1)(yx)ai2(yx+1)
那么上莫队维护平方和即可
排序可利用块的奇偶性进行优化

代码:

#include 

#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)

#define N 50005

using namespace std;

typedef long long ll;

struct Node {
    int l, r, id;
}q[N*10];
int beln[N], cnt[N], a[N], n, m;
ll ans[N][2], now;

void read(int &x) {
	int f = 1; x = 0; char s = getchar();
	while (s < '0' || s > '9') { if (s == '-') f = - 1; s = getchar(); }
	while (s >= '0' && s <= '9') { x = x * 10 + (s - '0'); s = getchar(); }
	x = x * f;
}

bool cmp(Node aa, Node bb) {
    return (beln[aa.l] == beln[bb.l]) ? ((beln[aa.l] & 1) ? aa.r < bb.r : aa.r > bb.r): beln[aa.l] < beln[bb.l];
}

void add(int x) {
    now -= 1ll * cnt[a[x]] * cnt[a[x]];
	++cnt[a[x]];
	now += 1ll * cnt[a[x]] * cnt[a[x]];
}

void del(int x) {
    now -= 1ll * cnt[a[x]] * cnt[a[x]];
	--cnt[a[x]];
	now += 1ll * cnt[a[x]] * cnt[a[x]];
}

ll Get_gcd(ll x, ll y) {
	return (!y) ? x : Get_gcd(y, x % y);
}

void write(int x) {
    if (x > 9) write(x / 10);
    putchar(x % 10 + '0');
}

int main() {
    read(n); read(m);
    int siz = sqrt(n);
    rep(i, 1, n) beln[i] = (i - 1) / siz + 1;         
    rep(i, 1, n) read(a[i]);
    rep(i, 1, m) read(q[i].l), read(q[i].r), q[i].id = i;
    sort(q + 1, q + m + 1, cmp);
    int l = 1, r = 0;
    rep(i, 1, m) {
        while (l < q[i].l) del(l), l++;
        while (l > q[i].l) l--, add(l);
        while (r < q[i].r) r++, add(r);
        while (r > q[i].r) del(r), r--;
        ans[q[i].id][0] = now - 1ll * (q[i].r - q[i].l + 1);
        ans[q[i].id][1] = 1ll * (q[i].r - q[i].l + 1) * (q[i].r - q[i].l);
    }
    ll Gcd;
    rep(i, 1, m) {
	    if (ans[i][0] && ans[i][1]) Gcd = Get_gcd(ans[i][0], ans[i][1]), ans[i][0] /= Gcd, ans[i][1] /= Gcd;
            else if (!ans[i][0]) ans[i][1] = 1;
	}
	rep(i, 1, m) write(ans[i][0]), printf("/"), write(ans[i][1]), printf("\n");
    return 0;
}

你可能感兴趣的:(C++,莫队)