裸的莫队算法题目。区间[l,r]一共有 C2r−l+1=(r−l)(r−l+1)2 种选取袜子的方案,假设在区间[l,r]内颜色为x的袜子有k只,那么有 C2k=k(k−1)2 种选取方案。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define MAXN 50010
using namespace std;
typedef long long LL;
int a[MAXN],n,m,block;
LL now,cnt[MAXN];
struct fs
{
LL fz,fm;
}ans[MAXN];
LL gcd(LL a,LL b)
{
return b==0?a:gcd(b,a%b);
}
struct Q
{
int l,r,id;
bool operator <(const Q &b)const
{
if(l/block == b.l/block) return r < b.r;
return l < b.l;
}
}que[MAXN];
void add(int x)
{
now -= cnt[x]*(cnt[x]-1)/2;
cnt[x]++;
now += cnt[x]*(cnt[x]-1)/2;
}
void del(int x)
{
now -= cnt[x]*(cnt[x]-1)/2;
cnt[x]--;
now += cnt[x]*(cnt[x]-1)/2;
}
int main()
{
scanf("%d%d",&n,&m);
block = sqrt(n);
for(int i = 1; i <= n; i++)
scanf("%d",&a[i]);
for(int i = 0; i < m; i++)
{
scanf("%d%d",&que[i].l,&que[i].r);
que[i].id = i;
}
sort(que,que+m);
int currentL = 1,currentR = 0;
for(int i = 0; i < m; i++)
{
while(que[i].l < currentL) add(a[--currentL]);
while(que[i].l > currentL) del(a[currentL++]);
while(que[i].r > currentR) add(a[++currentR]);
while(que[i].r < currentR) del(a[currentR--]);
if(que[i].l == que[i].r)
{
ans[que[i].id].fz = 0;
ans[que[i].id].fm = 1;
continue;
}
ans[que[i].id].fz = now;
ans[que[i].id].fm = 1LL*(que[i].r-que[i].l)*(que[i].r-que[i].l+1)/2;//分母应该是长整形,调了半天QAQ
LL d = gcd(now,ans[que[i].id].fm);
ans[que[i].id].fz /= d;
ans[que[i].id].fm /= d;
}
for(int i = 0; i < m; i++)
printf("%lld/%lld\n",ans[i].fz,ans[i].fm);
}