题目:洛谷P1494、BZOJ2038。
题目大意:给你一列袜子的颜色,每次要你求从区间$[L,R]$内随机选两个袜子颜色相同的概率。
解题思路:
首先,对于某个特定区间$[L,R]$,它的概率是$frac{sumlimits_{i=1}^{n}frac{C_i imes (C_i-1)}{2}}{frac{(R-L+1) imes(R-L)}{2}}$,其中$C_i$表示在$[L,R]$内,颜色$i$的出现次数。
然后,$R-L+1$和$R-L$是可以直接求的。
重点在于求上面那个玩意儿。我们发现,如果$C_i$增加$1$,那么答案将会增加原来的$C_i$(减$1$同理)。
所以我们可以在知道$[L,R]$的答案的情况下,用$O(1)$的时间得到$[Lpm 1,R]$或$[L,Rpm 1]$的答案。
然后莫队即可。
C++ Code:
#include<bits/stdc++.h> #define belong(i) ((i-1)/sz+1) #define N 50005 #define ll long long int n,sz,m,a[N],cnt[N]={0},p[N]; ll ans[N]; inline int readint(){ int c=getchar(); for(;!isdigit(c);c=getchar()); int d=0; for(;isdigit(c);c=getchar()) d=(d<<3)+(d<<1)+(c^'0'); return d; } struct Q{ int l,r,num; bool operator <(const Q& rhs)const{ if(belong(l)!=belong(rhs.l))return l<rhs.l; return r<rhs.r; } }q[N]; int main(){ n=readint(),m=readint(); sz=int(sqrt(n)+1e-5); for(int i=1;i<=n;++i)a[i]=readint(); for(int i=1;i<=m;++i)q[i].l=readint(),q[i].r=readint(),q[i].num=i; std::sort(q+1,q+m+1); int l=1,r=1; ll now=0; ++cnt[a[1]]; for(int i=1;i<=m;++i){ while(r<q[i].r)now+=cnt[a[++r]]++; while(l>q[i].l)now+=cnt[a[--l]]++; while(r>q[i].r)now-=--cnt[a[r--]]; while(l<q[i].l)now-=--cnt[a[l++]]; p[q[i].num]=r-l+1; ans[q[i].num]=now; } for(int i=1;i<=m;++i){ if(ans[i]==0){ putchar('0'),putchar('/'),putchar('1'),putchar(' '); continue; } int f=p[i]; ll x=std::__gcd(ans[i],(ll)f*(f-1)>>1); printf("%lld/%lld ",ans[i]/x,(ll)f*(f-1)/x>>1); } return 0; }