zoukankan      html  css  js  c++  java
  • 【洛谷1494】[国家集训队] 小Z的袜子(莫队)

    点此看题面

    大致题意:(N)只从(1sim N)编号的袜子,告诉你每只袜子的颜色,(M)组询问,每组询问给你一个区间([Lsim R]),让你求出小Z随机抽出(2)只袜子时有多大概率抽到两只颜色相同的袜子。

    题意转换

    假设这些袜子中共有(K)种颜色,则对于第(i)种颜色的袜子,抽到两次的概率为$$frac{cnt[i](cnt[i]-1)}{(R-L+1)(R-L)}$$

    那么,在整个区间中抽到两只相同颜色的袜子的概率就是$$sum_{i=1}^Kfrac{cnt[i](cnt[i]-1)}{(R-L+1)(R-L)}$$

    即$$frac{sum_{i=1}^Kcnt[i](cnt[i]-1)}{(R-L+1)(R-L)}$$

    莫队

    这时,我们就不难发现,对于一个区间,只要知道这个区间中每种颜色的袜子的出现次数就可以了。于是,就很容易想到用莫队来求解。

    我们只要记录每种颜色的袜子的出现次数,并在每次更新指针的同时更新(ans)即可。

    代码

    #include<bits/stdc++.h>
    #define LL long long
    #define N 50000
    #define M 50000
    using namespace std;
    LL n,Q,a[N+5],pos[N+5],ans1[M+5],ans2[M+5],cnt[N+5];
    struct Query
    {
        LL l,r,pos;
    }q[M+5];
    inline char tc()
    {
        static char ff[100000],*A=ff,*B=ff;
        return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(LL &x)
    {
        x=0;char ch;
        while(!isdigit(ch=tc()));
        while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    }
    inline void write(LL x)
    {
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
    }
    inline bool cmp(Query x,Query y)
    {
        return pos[x.l]<pos[y.l]||(pos[x.l]==pos[y.l]&&(pos[x.l]&1?x.r<y.r:x.r>y.r));
    }
    inline LL gcd(LL x,LL y)//求最大公因数,为之后的约分做准备
    {
        return y?gcd(y,x%y):x;
    }
    int main()
    {
        register LL i;
        for(read(n),read(Q),i=1;i<=n;++i) read(a[i]),pos[i]=(i-1)/sqrt(n)+1;
        for(i=1;i<=Q;++i) read(q[i].l),read(q[i].r),q[i].pos=i;
        sort(q+1,q+Q+1,cmp);
        LL ans=0,L=q[1].l,R=q[1].r;
        for(i=L;i<=R;++i)//先暴力求解第一个问题的答案
        {
            if(++cnt[a[i]]) ans-=((cnt[a[i]]-1)*(cnt[a[i]]-2));
            ans+=cnt[a[i]]*(cnt[a[i]]-1);
        }
        LL t1=ans,t2=(q[1].r-q[1].l+1)*(q[1].r-q[1].l),g=gcd(t1,t2);
        ans1[q[1].pos]=t1/g,ans2[q[1].pos]=t2/g;
        for(i=2;i<=Q;++i)
        {
            if(q[i].l==q[i].r)//题目中的附加说明,对于L=R的情况直接输出0/1
            {
                ans1[q[i].pos]=0,ans2[q[i].pos]=1;
                continue;
            }
            while(L<q[i].l) ans-=cnt[a[L]]*(cnt[a[L]]-1),--cnt[a[L]],ans+=cnt[a[L]]*(cnt[a[L]]-1),++L;//若L指针小于当前询问的l,就先更新ans,再移动指针
            while(L>q[i].l) --L,ans-=cnt[a[L]]*(cnt[a[L]]-1),++cnt[a[L]],ans+=cnt[a[L]]*(cnt[a[L]]-1);//若L指针大于当前询问的l,则操作顺序与上面的操作恰好相反
            while(R>q[i].r) ans-=cnt[a[R]]*(cnt[a[R]]-1),--cnt[a[R]],ans+=cnt[a[R]]*(cnt[a[R]]-1),--R;//R指针的操作与L指针类似
            while(R<q[i].r) ++R,ans-=cnt[a[R]]*(cnt[a[R]]-1),++cnt[a[R]],ans+=cnt[a[R]]*(cnt[a[R]]-1);
            LL t1=ans,t2=(q[i].r-q[i].l+1)*(q[i].r-q[i].l),g=gcd(t1,t2);//注意约分
            ans1[q[i].pos]=t1/g,ans2[q[i].pos]=t2/g;
        }
        for(i=1;i<=Q;++i) write(ans1[i]),putchar('/'),write(ans1[i]?ans2[i]:1),putchar('
    ');
        return 0;
    }
    
  • 相关阅读:
    MSVCRTD.lib(crtexe.obj) : error LNK2019: 无法解析的外部符号 _main,该符号在函数 ___tmainCRTStart
    (转)Spring MVC
    ios>android>javaee
    css标准导航代码
    图片对齐问题
    display:inline、block、inline-block的区别
    css怎么引用某张图片?链接要怎么写
    论怎么写好一篇实验报告
    路由器及其配置方法
    (转)MyEclipse2014配置Tomcat开发JavaWeb程序JSP以及Servlet
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu1494.html
Copyright © 2011-2022 走看看