n个袜子每个都有一个颜色,求他给的区间 取两个袜子正好同色的概率
复杂度nsqrt(n);
先分sqrt(n)块 然后把区间按最左边界所在的块排序,如果所在块相等按右边届从小到大排序。
定义此时的l,r,ans(起始为1,0,0),然后枚举区间改变l,r,ans
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
#define MAXN 50010
using namespace std;
int n,m,unit;
int num[MAXN],co[MAXN];
struct node{
int l,r,i;
}no[51000];
LL gcd(LL a,LL b)
{
while(b)
{
LL t = b;
b = a%b;
a = t;
}
return a;
}
class node2{
public:
LL a,b;
inline void gao()
{
LL t = gcd(a,b);
a/=t;
b/=t;
}
}ans1[MAXN];
inline bool cmp(node no1,node no2)//排序
{
if(no1.l/unit!=no2.l/unit)return no1.l<no2.l;
return no1.r<no2.r;
}
inline void work()//莫队
{
int l = 1,r = 0;
LL ans = 0;
for(int i=0;i<m;i++)
{
while(r>no[i].r)
{
ans-=(LL)num[co[r]]*(num[co[r]]-1);
num[co[r]]--;
ans+=(LL)num[co[r]]*(num[co[r]]-1);
r--;
}
while(r<no[i].r)
{
r++;
ans-=(LL)num[co[r]]*(num[co[r]]-1);
num[co[r]]++;
ans+=(LL)num[co[r]]*(num[co[r]]-1);
}
while(l<no[i].l)
{
ans-=(LL)num[co[l]]*(num[co[l]]-1);
num[co[l]]--;
ans+=(LL)num[co[l]]*(num[co[l]]-1);
l++;
}
while(l>no[i].l)
{
l--;
ans-=(LL)num[co[l]]*(num[co[l]]-1);
num[co[l]]++;
ans+=(LL)num[co[l]]*(num[co[l]]-1);
}
ans1[no[i].i].a = ans;
ans1[no[i].i].b = ((LL)no[i].r-no[i].l+1)*(no[i].r-no[i].l);
ans1[no[i].i].gao();
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&co[i]);
for(int i=0;i<m;i++)
{
scanf("%d%d",&no[i].l,&no[i].r);
no[i].i = i;
}
unit = sqrt(m+0.001);
sort(no,no+m,cmp);
work();
for(int i=0;i<m;i++)
printf("%lld/%lld\n",ans1[i].a,ans1[i].b);
return 0;
}