P1494 [国家集训队] 小 Z 的袜子

P1494 [国家集训队] 小 Z 的袜子

题目描述

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

具体来说,小 Z 把这 \(N\) 只袜子从 \(1\)\(N\) 编号,然后从编号 \(L\)\(R\) 的袜子中随机选出两只来穿。尽管小 Z 并不在意两只袜子是不是完整的一双,他却很在意袜子的颜色,毕竟穿两只不同色的袜子会很尴尬。

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

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

提示

\(100\%\) 的数据中,\(N,M \leq 50000\)\(1 \leq L \leq R \leq N\)\(C_i \leq N\)

Solution :

十分简单的莫队,非常适合入门。
我们发现分母是很容易确定的,所以我们统计分子就好了。考虑用桶维护区间内的颜色出现次数 \(bac_{col}\),我们新加一个节点 \(x\) ,假设其颜色为 \(bac_{col}\) \(col_x\) 那么区间内的点对 \(x\) 产生的贡献就是 \(bac_{col_{x}}\)

那么这个贡献显然是可以 \(O(1)\) 转移的,我们直接上莫队。

至于莫队算法嘛:

我似乎不能用比较精炼的语言概括其思想,但是它能应用的特征十分明显:询问离线,无修改操作,插入或删除一个点时,重新统计贡献的复杂度不高。

算法流程:

我们将所有询问排序,用两个指针 \(l,r\) 维护当前区间,在状态转移时移动指针。

Code:

#include<bits/stdc++.h>
#define int long long 
const int N=5e4+5;
using namespace std;
int a[N],bac[N],blo[N],ans[N],len[N];
struct task{
    int l,r,L,R,id;
    bool operator<(const task &t)const{
        return l==t.l ? (l&1 ? R<t.R : t.R<R) :l < t.l;
    }
}q[N];
int n,m,S,sum;
inline void add(int x){sum+=bac[a[x]]++;}
inline void del(int x){sum-=--bac[a[x]];}
int gcd(int x,int y){return y ? gcd(y,x%y) : x;}
void work()
{
    cin>>n>>m;
    S=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lld",&a[i]);
        blo[i]=(i-1)/S+1;
    }
    for(int i=1,l,r;i<=m;i++)
    {
        scanf("%lld%lld",&l,&r);
        q[i]={blo[l],blo[r],l,r,i};
        len[i]=r-l+1;
    }
    sort(q+1,q+1+m);
    int l=1,r=0;
    for(int i=1;i<=m;i++)
    {
        while(r<q[i].R)add(++r);
        while(l<q[i].L)del(l++);
        while(q[i].L<l)add(--l);
        while(q[i].R<r)del(r--);
        ans[q[i].id]=sum<<1;
    }
    for(int i=1;i<=m;i++)
    {
        len[i]*=len[i]-1;
        if(len[i])
        {
            int d=gcd(ans[i],len[i]);
            printf("%lld/%lld\n",ans[i]/d,len[i]/d);
        }
        else
        {
            printf("0/1\n");
        }
    }
}
#undef int
int main()
{
    //freopen("P1494_1.in","r",stdin);freopen("P1494.out","w",stdout);
    work();
    return 0;
}
posted @ 2025-02-19 14:11  liuboom  阅读(22)  评论(0)    收藏  举报