zoukankan      html  css  js  c++  java
  • [题解]luogu-P1494 小Z的袜子 普通莫队

    原题戳

    不会莫队?再戳

    此题是普通莫队第一题,考虑每个询问,我们排序后,用一个数组(s)记录每个数在当前区间出现次数。
    不难得出,第(num)个袜子对第(i)个询问的贡献即为每次从s[color[num]]个袜子里选出两个袜子的概率,即

    [frac{ egin{pmatrix} 2 \ s[color[num]] \ end{pmatrix}}{ egin{pmatrix} 2 \ (q[i].r - q[i].l + 1) \ end{pmatrix} } ]

    可列开为

    [frac{s[color[num]]*(s[color[num]] - 1) / 2}{(q[i].r - q[i].l + 1) * (q[i].r - q[i].l) / 2} ]

    化简得

    [frac{s[color[num]]*(s[color[num]] - 1)}{(q[i].r - q[i].l + 1) * (q[i].r - q[i].l)} ]

    每个问题的区间我们可以另开一个数组记录,在最后输出答案的时候输出就可以了
    所以我们只用维护一个(s)数组,代码如下

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    
    typedef long long LL;
    const int N = 50030;
    
    int n, m, blo, L, R;
    int c[N], id[N], s[N];
    LL sum, gcd;
    LL Ans[N], l[N], r[N];
    
    struct question
    {
        int l, r, num;
    } q[N];
    
    int cmp(question x, question y)
    {
        if (id[x.l] != id[y.l]) return id[x.l] < id[y.l]; 
        if (id[x.l] % 2 == 1) return x.r < y.r;
        else return x.r > y.r;
    }
    
    LL GCD(LL a, LL b)
    {
        if (b == 0) return a;
        else return GCD(b, a % b);
    }
    
    int main()
    {
        scanf ("%d%d", &n, &m);
        blo = sqrt(n);
        for (int i = 1; i <= n; ++i)
        {   
            scanf ("%d", &c[i]);
            id[i] = (i - 1) / blo + 1;
        }
        for (int i = 1; i <= m; ++i) 
        {
            scanf ("%lld%lld", &l[i], &r[i]);
            q[i].l = l[i];
            q[i].r = r[i];
            q[i].num = i;
        }
        
        std::sort(q + 1, q + m + 1, cmp);
        
        L = 1;
        for (int i = 1; i <= m; ++i)
        {
            while (L > q[i].l) {--L; sum -= s[c[L]] * (s[c[L]] - 1) / 2; s[c[L]]++; sum += s[c[L]] * (s[c[L]] - 1) / 2;}
            while (R < q[i].r) {++R; sum -= s[c[R]] * (s[c[R]] - 1) / 2; s[c[R]]++; sum += s[c[R]] * (s[c[R]] - 1) / 2;}
            while (L < q[i].l) {sum -= s[c[L]] * (s[c[L]] - 1) / 2; --s[c[L]]; sum += s[c[L]] * (s[c[L]] - 1) / 2; ++L;}
            while (R > q[i].r) {sum -= s[c[R]] * (s[c[R]] - 1) / 2; --s[c[R]]; sum += s[c[R]] * (s[c[R]] - 1) / 2; --R;}
            Ans[q[i].num] = sum;//扩张在前,缩小在后
        }
    
        for (int i = 1; i <= m; ++i)
        {
            gcd = GCD(Ans[i], (r[i] - l[i]) * (r[i] - l[i] + 1) / 2);
            if (l[i] == r[i]) printf ("0/1
    ");
            else printf ("%lld/%lld
    ", Ans[i] / gcd, ((r[i] - l[i]) * (r[i] - l[i] + 1) / 2) / gcd);
        }
    
        return 0;
    }``
  • 相关阅读:
    Pretty girl,你一定要去旅行
    难受就哭,开心就笑
    你对你的大学生活满意吧
    [leetCode]575. 分糖果
    [leetCode]383.赎金信
    242. 有效的字母异位词
    [leetCode]538. 把二叉搜索树转换为累加树
    [leetCode]面试题 02.07. 链表相交
    [leetCode]206. 反转链表
    [leetCode]707. 设计链表
  • 原文地址:https://www.cnblogs.com/martixx/p/13569773.html
Copyright © 2011-2022 走看看