洛谷P1494 [国家集训队]小Z的袜子 题解 普通莫队算法

题目链接:https://www.luogu.com.cn/problem/P1494

解题思路:

普通莫队算法。

使用 (c[i]) 表示第 (i) 只袜子的颜色、(cnt[i]) 表示当前区间颜色 (i) 的袜子数量,
同时维护 (res) 记录当前的区间中存在多少对相同颜色的袜子。

对于当前区间 ([l,r]) ,总对数为 (tot = frac{(r-l+1) imes (r-l)}{2}),所以比值为 (frac{res}{tot})(注意可能需要约分)。

示例代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 50050;
int n, m, sn, c[maxn], cnt[maxn];
long long res;
pair<long long, long long> ans[maxn];
struct Query {
    int l, r, id;
    bool operator < (const Query &b) const {
        return l / sn < b.l / sn || l / sn == b.l / sn && r < b.r;
    }
} q[maxn];
void add(int i) {
    res += cnt[c[i]];
    cnt[c[i]] ++;
}
void del(int i) {
    cnt[c[i]] --;
    res -= cnt[c[i]];
}
int main() {
    scanf("%d%d", &n, &m);
    sn = sqrt(n);
    for (int i = 1; i <= n; i ++) scanf("%d", c+i);
    for (int i = 0; i < m; i ++) {
        scanf("%d%d", &q[i].l, &q[i].r);
        q[i].id = i;
    }
    sort(q, q+m);
    for (int i = 0, l = 1, r = 0; i < m; i ++) {
        if (q[i].l == q[i].r) {
            ans[q[i].id] = { 0, 1 };
            continue;
        }
        while (l > q[i].l) add(--l);
        while (r < q[i].r) add(++r);
        while (l < q[i].l) del(l++);
        while (r > q[i].r) del(r--);
        if (res == 0) ans[q[i].id] = { 0, 1 };
        else {
            long long tot = (long long)(r - l + 1) * (r - l) / 2;
            long long tmp = __gcd(res, tot);
            ans[q[i].id] = { res/tmp, tot/tmp };
        }
    }
    for (int i = 0; i < m; i ++) printf("%lld/%lld
", ans[i].first, ans[i].second);
    return 0;
}

参考资料:http://oi-wiki.com/misc/mo-algo/

原文地址:https://www.cnblogs.com/quanjun/p/14318856.html