[国家集训队]小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
",ans[i],ans2[i]);
58     return 0;
59 }
[国家集训队]小Z的袜子
原文地址:https://www.cnblogs.com/szmssf/p/11564593.html