题目:
题解:
假设在LR这段区间里颜色为
x,y,z…
的袜子分别有
a,b,c…
个。
那么概率(利用排列组合推导)
p=a(a−1)2+b(b−1)2+c(c−1)2+…(R−L+1)(R−L)2
=a2+b2+c2+…−(a+b+c+…)(R−L+1)(R−L)
a2+b2+c2+…−(R−L+1)(R−L+1)(R−L)
那么我们用莫队算法+分块乱搞就能求出答案。
O(nn−−√)
对于时间复杂度的比较:空间换时间,效率++;重载运算符,效率+++++;成员函数≈非成员函数。
莫队算法的实现步骤为:
1、先对原序列进行分块。
2、离线操作,对询问进行排序,以左端点所在块编号 为第一关键字,右端点的位置为第二关键字,进行排序。然后维护[
l
,
r
]的答案,并不断调整
l
和
r
。
代码:
#include <cstdio>
#include <algorithm>
#include <cmath>
#define LL long long
using namespace std;
LL gcd(LL a,LL b){return (b==0)?a:gcd(b,a%b);}
int num[50005],pos[50005],m,n,a[50005];
struct hh
{
int id,l,r;LL a,b;
/* void modify()
{
LL k=gcd(a,b);
a/=k,b/=k;
}*/
}nod[50005];
int cmp1(hh a,hh b){return a.id<b.id;}
bool operator < (const hh &R,const hh &T)
{
return pos[R.l]<pos[T.l] || (pos[R.l]==pos[T.l] && R.r<T.r);
}
int cmp(hh a,hh b)
{
if (pos[a.id]==pos[b.id]) return a.r<b.r;
return pos[a.id]<pos[b.id];
}
void simply(LL a,LL b,int id)
{
LL c=gcd(a,b);
a/=c; b/=c;
nod[id].a=(LL)a; nod[id].b=(LL)b;
}
void modi(LL &ans,int add,int i)
{
ans=ans+2*add*num[a[i]]+1;
num[a[i]]+=add;
}
void work()
{
int i,l=1,r=0;
LL ans=0;
for (i=1;i<=m;i++)
{
while (r<nod[i].r)
{
r++;
modi(ans,1,r);
}
while (r>nod[i].r)
{
modi(ans,-1,r);
r--;
}
while (l<nod[i].l)
{
modi(ans,-1,l);
l++;
}
while (l>nod[i].l)
{
l--;
modi(ans,1,l);
}
if (nod[i].l==nod[i].r)
{
nod[i].a=0; nod[i].b=1;
continue;
}
nod[i].a=(LL)ans-(r-l+1);nod[i].b=(LL)(r-l+1)*(r-l);
// nod[i].modify();
simply(nod[i].a,nod[i].b,i);
}
sort(nod+1,nod+1+m,cmp1);
for (i=1;i<=m;i++)
printf("%lld/%lld\n",nod[i].a,nod[i].b);
}
int main()
{
int i;
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
for (i=1;i<=m;i++)
{
nod[i].id=i;
scanf("%d%d",&nod[i].l,&nod[i].r);
}
int unit=(int)sqrt(n);
for (i=1;i<=n;i++)
pos[i]=(i-1)/unit+1;
sort(nod+1,nod+m+1);
work();
}