zoukankan      html  css  js  c++  java
  • BZOJ

    题目链接:小Z的袜子

    题意:$n$只袜子,$m$个询问,每次回答有多大概率在$[L,R]$区间内抽到两只颜色相同的袜子

    思路:普通莫队,如果两个询问左端点在一个块内,则按询问右端点排序,否则按照所在块的序号排序,维护一个数组$num$,表示在区间$[L,R]$中,颜色为$c$的袜子有$num[c]$只,令变量$res=sum_{c}num[c]*(num[c]-1)/2$,显然对于每个区间$[L,R]$抽到同色袜子的概率就是$frac{res}{C_{R-L+1}^{2}}$,每次移动区间时修改$num[c]$,同时更新$res$即可,时间复杂度$O(n^{frac{3}{2}})$

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    
    using namespace std;
    
    typedef long long ll;
    
    const int N = 50010;
    
    struct node {
        int l, r, id;
    };
    
    int n, m, a[N];
    int block, belong[N], tot, l[N], r[N];
    ll num[N], res, mol[N], den[N];
    node q[N];
    
    void build()
    {
        block = sqrt(n);
        tot = n / block;
        if (n % block) tot++;
        for (int i = 1; i <= tot; i++) {
            l[i] = (i - 1) * block + 1;
            r[i] = i * block;
        }
        r[tot] = n;
        for (int i = 1; i <= n; i++)
            belong[i] = (i - 1) / block + 1;
    }
    
    bool cmp(node a, node b)
    {
        if (belong[a.l] != belong[b.l])
            return belong[a.l] < belong[b.l];
        return a.r < b.r;
    }
    
    void add(int x)
    {
        res = res - num[a[x]] * (num[a[x]] - 1) / 2;
        num[a[x]]++;
        res = res + num[a[x]] * (num[a[x]] - 1) / 2;
    }
    
    void sub(int x)
    {
        res = res - num[a[x]] * (num[a[x]] - 1) / 2;
        num[a[x]]--;
        res = res + num[a[x]] * (num[a[x]] - 1) / 2;
    }
    
    ll c(int n)
    {
        return (ll)n * (n - 1) / 2;
    }
    
    ll gcd(ll a, ll b)
    {
        return 0 == b ? a : gcd(b, a % b);
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        build();
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
        for (int i = 1; i <= m; i++) {
            scanf("%d%d", &q[i].l, &q[i].r);
            den[i] = c(q[i].r - q[i].l + 1);
            q[i].id = i;
        }
        sort(q + 1, q + m + 1, cmp);
        int L = 1, R = 0;
        for (int i = 1; i <= m; i++) {
            while (q[i].l < L) add(--L);
            while (q[i].r > R) add(++R);
            while (q[i].l > L) sub(L++);
            while (q[i].r < R) sub(R--);
            mol[q[i].id] = res;
        }
        for (int i = 1; i <= m; i++) {
            ll d = gcd(mol[i], den[i]);
            if (0 == mol[i]) printf("0/1
    ");
            else printf("%lld/%lld
    ", mol[i] / d, den[i] / d);
        }
        return 0;
    }
  • 相关阅读:
    linux上的常用的进程与内存优化命令
    ubuntu 上运行的django 出现No space left on device错误
    openstack 使用pbr配置,setup.cfg的格式与含义
    openstack中安装包与组件
    对drf序列化器的理解
    对商品数据表的理解
    首页广告数据表的理解
    对省市区地址的理解
    对邮箱验证的理解
    用户中心个人信息实现的理解
  • 原文地址:https://www.cnblogs.com/zzzzzzy/p/12336067.html
Copyright © 2011-2022 走看看