进行区间询问[l,r],输出该区间内随机抽两次抽到相同颜色袜子的概率。
一个区间可以选取的总数是 C(r-l+1,2), 这个是分母, 分子是 C(区间颜色,2)
ans 代表分子,是区间求和,每种颜色可以选择的可能。
莫队算法的复杂度是 n*sqrt(n);
#include <bits/stdc++.h>
#define mem(x,v) memset(x,v,sizeof(x))
#define go(i,a,b) for (int i = a; i <= b; i++)
#define og(i,a,b) for (int i = a; i >= b; i--)
using namespace std;
typedef long long LL;
const double EPS = 1e-10;
const int INF = 0x3f3f3f3f;
const int N = 5e4+10;
int col[N],unit,Be[N];
struct Mo{
int l,r,ID;
LL A,B;
}f[N];
LL ans,sum[N];
LL GCD(LL a, LL b){
if (b == 0) return a; else return GCD(b,a%b);
}
LL S(LL x){return x*(x-1);}
bool cmp(Mo const &aa, Mo const &bb){
if (Be[aa.l] == Be[bb.l]) return aa.r < bb.r;
return aa.l < bb.l;
}
bool CMP(Mo const &aa, Mo const &bb){return aa.ID < bb.ID;}
void action(int x, int y){ans -= S(sum[col[x]]); sum[col[x]] += y; ans+=S(sum[col[x]]);}
int main(){
int n,m;
scanf("%d%d",&n,&m);
unit = sqrt(n);
go(i,1,n)scanf("%d",&col[i]),Be[i] = i/unit+1; //这个地方 莫队分块。
go(i,1,m) scanf("%d%d",&f[i].l,&f[i].r),f[i].ID = i;
sort(f+1,f+m+1,cmp);
int l = 1,r = 0;
go(i,1,m){
while(l < f[i].l) action(l,-1),l++; //好多 while 语句。
while(l > f[i].l) action(l-1,1),l--;
while(r < f[i].r) action(r+1,1),r++;
while(r > f[i].r) action(r,-1),r--;
if (f[i].l == f[i].r) {f[i].A = 0,f[i].B = 1;continue;}
f[i].A = ans; f[i].B = S(f[i].r - f[i].l + 1);
LL gcd = GCD(f[i].A,f[i].B);
f[i].A /= gcd; f[i].B /= gcd;
}
sort(f+1,f+m+1,CMP);
go(i,1,m) printf("%lld/%lld\n",f[i].A,f[i].B);
return 0;
}