[国家集训队]小Z的袜子
设当前询问端点为$l,r$,则目前有$n$中不同颜色的袜子,分别是$a_1,a_2...a_n$,第$i$种颜色的袜子有$cnt_i$只
则抽到两只袜子的情况数有$cnt_1*(cnt_1-1)/2+cnt_2*(cnt_2-1)/2+......+cnt_n*(cnt_n-1)/2$种。
化简:$cnt_1*(cnt_1-1)/2+cnt_2*(cnt_2-1)/2+......+cnt_n*(cnt_n-1)/2\\=>(cnt_1*cnt_1+cnt_2*cnt_2+......+cnt_n*cnt_n-cnt_1-cnt_2-......-cnt_n)/2\\=>(cnt_1*cnt_1+cnt_2*cnt_2+......+cnt_n*cnt_n-(r-l+1))/2\\$
总情况数有$(r-l+1)*(r-l)/2$种
分子、分母同时乘2,就变成了这样一个问题:
求$\frac{(cnt_1*cnt_1+cnt_2*cnt_2+......+cnt_n*cnt_n-(r-l+1))}{(r-l+1)*(r-l)}$
然后我们只需要维护一个区间内每种颜色个数的平方和。
离线后莫队维护即可。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define int long long 7 #define N 50005 8 using namespace std; 9 int read() 10 { 11 int x=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} 14 return x*f; 15 } 16 int n,m,a[N],cnt[N],l=1,r=0,ans[N],ans2[N],siz,now; 17 struct node 18 { 19 int l,r,x; 20 }q[N]; 21 bool cmp(node a,node b) 22 { 23 if((a.l+siz-1)/siz!=(b.l+siz-1)/siz)return (a.l+siz-1)/siz<(b.l+siz-1)/siz; 24 return a.r<b.r; 25 } 26 signed main() 27 { 28 n=read();m=read(); 29 for(int i=1;i<=n;i++)a[i]=read(); 30 for(int i=1;i<=m;i++) 31 { 32 q[i].l=read();q[i].r=read(); 33 q[i].x=i; 34 } 35 siz=sqrt(n); 36 sort(q+1,q+1+m,cmp); 37 for(int i=1;i<=m;i++) 38 { 39 int ll=q[i].l,rr=q[i].r; 40 if(ll==rr) 41 { 42 //cout<<"----------------"<<endl; 43 ans[q[i].x]=0; 44 ans2[q[i].x]=1; 45 continue; 46 } 47 while(l<ll)--cnt[a[l]],now-=cnt[a[l]]*2+1,l++; 48 while(l>ll)l--,cnt[a[l]]++,now+=cnt[a[l]]*2-1; 49 while(r<rr)r++,cnt[a[r]]++,now+=cnt[a[r]]*2-1; 50 while(r>rr)--cnt[a[r]],now-=cnt[a[r]]*2+1,r--; 51 ans[q[i].x]=now-(rr-ll+1); 52 ans2[q[i].x]=(long long)(rr-ll+1)*(rr-ll); 53 int gcd=__gcd(ans[q[i].x],ans2[q[i].x]); 54 ans[q[i].x]/=gcd; 55 ans2[q[i].x]/=gcd; 56 } 57 for(int i=1;i<=m;i++)printf("%lld/%lld\n",ans[i],ans2[i]); 58 return 0; 59 }