[國家集訓隊]小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\n",a/c,b/c);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章