给出m个查询[l,r],问[l,r]区间内随机拿出两双相同袜子的概率。
基础莫队题。对查询进行分块排序后,对l,r区间移来移去统计一下。
这里卡常数,比较器里面不能有除法。
int block_num;
struct query{
int l,r,id;
int block;
bool operator<(const query &q) const{
if(block != q.block) return l<q.l;
return ((q.block)&1)? r < q.r : q.r<r;
}
}q[N];
int len,id[N];
int c[N],num[N];
ll sum, tot[N],cnt[N];
bool cmp(query x,query y){
if (id[x.l]==id[y.l]){
if ((id[x.l]&1)==1) return x.r<y.r;
else return x.r>y.r;
}
else return id[x.l]<id[y.l];
}
ll gcd(ll a, ll b){
return b?gcd(b,a%b):a;
}
ll ct(int num){
return 1ll*num*(num-1);
}
void add(int idx){
sum -= ct(num[idx]);
sum += ct(++num[idx]);
}
void del(int idx){
sum -= ct(num[idx]);
sum += ct(--num[idx]);
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
len=sqrt(n);
block_num = sqrt(n);
fr(i,1,n+1) {
scanf("%d",&c[i]);
id[i]=i/len;
}
fr(i,0,m) {
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id =i;
q[i].block = q[i].l/block_num;
}
clr(num);
sum = 0;
sort(q,q+m);
int l = 1, r = 0;
fr(i,0,m){
if(q[i].l == q[i].r){
cnt[q[i].id] = 0;
tot[q[i].id] = 1;
continue;
}
while(l>q[i].l) add(c[--l]);
while(r<q[i].r) add(c[++r]);
while(l<q[i].l) del(c[l++]);
while(r>q[i].r) del(c[r--]);
cnt[q[i].id] = sum;
int len = r-l+1;
tot[q[i].id] = ct(r-l+1);
}
fr(i,0,m){
ll gd = gcd(cnt[i],tot[i]);
printf("%lld/%lld\n",cnt[i]/gd, tot[i]/gd);
}
}