zoukankan      html  css  js  c++  java
  • [国家集训队]小Z的袜子

    题目描述

    作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中找出一双来穿。终于有一天,小Z再也无法忍受这恼人的找袜子过程,于是他决定听天由命……

    具体来说,小Z把这N只袜子从1到N编号,然后从编号L到R(L 尽管小Z并不在意两只袜子是不是完整的一双,甚至不在意两只袜子是否一左一右,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。

    你的任务便是告诉小Z,他有多大的概率抽到两只颜色相同的袜子。当然,小Z希望这个概率尽量高,所以他可能会询问多个(L,R)以方便自己选择。

    然而数据中有L=R的情况,请特判这种情况,输出0/1。

    输入格式

    输入文件第一行包含两个正整数N和M。N为袜子的数量,M为小Z所提的询问的数量。接下来一行包含N个正整数Ci,其中Ci表示第i只袜子的颜色,相同的颜色用相同的数字表示。再接下来M行,每行两个正整数L,R表示一个询问。

    输出格式

    包含M行,对于每个询问在一行中输出分数A/B表示从该询问的区间[L,R]中随机抽出两只袜子颜色相同的概率。若该概率为0则输出0/1,否则输出的A/B必须为最简分数。


    暴力一点,直接上莫队。

    这题就是莫队的板子题,唯一难的地方就是算概率。

    设cnt(x)当前区间内表示颜色x出现的次数。当一个新的颜色x的袜子出现时,它对答案的贡献就是:

    [(cnt(x)+1)*cnt(x)-cnt(x)*(cnt(x)-1)=2cnt(x) ]

    所以我们将答案加上2 * cnt(x)即可。

    而当删去一个颜色为x的袜子时,对答案的贡献就是:

    [cnt(x)*(cnt(x)-1)-(cnt(x)-1)*(cnt(x)-2)=2cnt(x)-2 ]

    所以我们将答案减去2(cnt(x)-1)即可

    对于最后的最简分数,将分子分母除以他俩的gcd即可。

    时间复杂度为O(N√N)

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #define maxn 50001
    #define maxm 50001
    using namespace std;
    int n,m,col[maxn];
    inline int read(){
        register int x(0),f(1); register char c(getchar());
        while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
        while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    
    struct query{
        int l,r,col,id;
        long long ans;
    }q[maxm];
    inline bool cmp(const query &a,const query &b){ return (a.col^b.col)?a.col<b.col:((a.col&1)?a.r>b.r:a.r<b.r); }
    inline bool cmp2(const query &a,const query &b){ return a.id<b.id; }
    int cnt[maxn],unit;
    long long tot;
    inline void add(const int &x){ tot+=2ll*cnt[col[x]],cnt[col[x]]++; }
    inline void del(const int &x){ cnt[col[x]]--,tot-=2ll*cnt[col[x]]; }
    inline void MoQueue(){
        sort(q+1,q+1+m,cmp);
        int l=1,r=0;
        for(register int i=1;i<=m;i++){
            while(l<q[i].l) del(l++);
            while(l>q[i].l) add(--l);
            while(r<q[i].r) add(++r);
            while(r>q[i].r) del(r--);
            q[i].ans=tot;
        }
        sort(q+1,q+1+m,cmp2);
    }
    
    long long gcd(long long a,long long b){ return b?gcd(b,a%b):a; }
    int main(){
        n=read(),m=read(),unit=sqrt(n);
        for(register int i=1;i<=n;i++) col[i]=read();
        for(register int i=1;i<=m;i++) q[i].l=read(),q[i].r=read(),q[i].col=q[i].l/unit+1,q[i].id=i;
        MoQueue();
        for(register int i=1;i<=m;i++){
            if(q[i].l==q[i].r){ puts("0/1"); continue; }
            long long a=q[i].ans,b=1ll*(q[i].r-q[i].l+1)*(q[i].r-q[i].l),c=gcd(a,b);
            printf("%lld/%lld
    ",a/c,b/c);
        }
        return 0;
    }
    
  • 相关阅读:
    测试及开发中应当要考虑的安全问题
    31、Python之会话管理cookie和session
    Scrapy爬虫框架入门
    30、Python之web框架django进阶篇
    装饰器函数
    函数初始后续与进阶
    函数初识
    文件操作
    日本语自学
    编码,集合
  • 原文地址:https://www.cnblogs.com/akura/p/11069225.html
Copyright © 2011-2022 走看看