不说题意了 传送门biu~
就是推一推公式然后维护这些值 但是我是没推公式的 做完之后才推哇 不推也可以过的
要求区间[l,r][l,r]内选出两个相同颜色的概率,即求
(C2cnt1+C2cnt2+...+C2cntk)/C2r−l+1
(
C
2
c
n
t
1
+
C
2
c
n
t
2
+
.
.
.
+
C
2
c
n
t
k
)
/
C
2
r
−
l
+
1
其中cnti为颜色为ii的袜子有多少个,所以
cnt1+cnt2+cnt3+...+cntk=r−l+1
c
n
t
1
+
c
n
t
2
+
c
n
t
3
+
.
.
.
+
c
n
t
k
=
r
−
l
+
1
所以刚才的式子就化为
(cnt21+cnt22+...+cnt2k−(r−l+1))/((r−l+1)∗(r−l))
(
c
n
t
21
+
c
n
t
22
+
.
.
.
+
c
n
t
2
k
−
(
r
−
l
+
1
)
)
/
(
(
r
−
l
+
1
)
∗
(
r
−
l
)
)
AC代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#define ll long long
using namespace std;
int n,m;
ll s[50050],ans=0;
int c[50050],pos[50050];
struct node{int l,r,poi;ll a,b;}a[50050];
bool cmp(node x,node y){if(pos[x.l]==pos[y.l]) return x.r<y.r; return x.l<y.l;}
bool cmpoi(node x,node y){return x.poi<y.poi;}
ll gcd(ll a,ll b)
{
if(!b) return a;
return gcd(b,a%b);
}
void push(int x){ans+=s[c[x]]++;}
void pop(int x){ans-=--s[c[x]];}
void solve()
{
for(int i=1,l=1,r=0;i<=m;i++)
{
while(l<a[i].l) pop(l++);
while(r>a[i].r) pop(r--);
while(l>a[i].l) push(--l);
while(r<a[i].r) push(++r);
if(a[i].l==a[i].r)
{
a[i].a=0,a[i].b=1;
continue;
}
a[i].a=ans;
a[i].b=1ll*(a[i].r-a[i].l+1)*(a[i].r-a[i].l)/2;
ll gcdd=gcd(a[i].a,a[i].b);
a[i].a/=gcdd,a[i].b/=gcdd;
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&c[i]);
int block=sqrt(n);
for(int i=1;i<=n;i++) pos[i]=(i-1)/block+1;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].l,&a[i].r);
a[i].poi=i;
}
sort(a+1,a+1+m,cmp);
solve();
sort(a+1,a+1+m,cmpoi);
for(int i=1;i<=m;i++) printf("%lld/%lld\n",a[i].a,a[i].b);
return 0;
}