对于L,R的询问。
设其中颜色为x,y,z..........的袜子的个数为a,b,c.......
那么答案即为 (a*(a-1)/2+b*(b-1)/2+c*(c-1)/2....)/((R-L+1)*(R-L)/2)(a∗(a−1)/2+b∗(b−1)/2+c∗(c−1)/2....)/((R−L+1)∗(R−L)/2)
化简得: (a^2+b^2+c^2+...x^2-(a+b+c+d+.....))/((R-L+1)*(R-L))(a2+b2+c2+...x2−(a+b+c+d+.....))/((R−L+1)∗(R−L))
即: (a^2+b^2+c^2+...x^2-(R-L+1))/((R-L+1)*(R-L))(a2+b2+c2+...x2−(R−L+1))/((R−L+1)∗(R−L))
我们需要解决的一个问题
求一个区间内每种颜色数目的平方和。
使用莫队的相关知识
#include<iostream>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define ll long long int
#define maxn 50010
ll n,m,vis[maxn],a[maxn];
ll num[maxn],ans=0,l,r;
typedef struct nodee{
int l,r,id;
ll a,b;
}node;
node maze[maxn];
ll gcd(ll a,ll b)
{
if(a%b==0)
return b;
return gcd(b,a%b);
}
bool cmp(node a,node b)
{
if(vis[a.l]==vis[b.l])
return a.r<b.r;
return a.l<b.l;
}
bool cmpp(node a,node b)
{
return a.id<b.id;
}
void pls(int x)
{
ans-=num[a[x]]*num[a[x]];
num[a[x]]+=1;
ans+=num[a[x]]*num[a[x]];
}
void min(int x)
{
ans-=num[a[x]]*num[a[x]];
num[a[x]]-=1;
ans+=num[a[x]]*num[a[x]];
}
int main()
{
cin>> n >> m;
for(int i=1;i<=n;i++)
cin >> a[i];
ll temp=(ll)sqrt((double)n);
memset(num,0,sizeof(num));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
vis[i]=(i-1)/temp+1;
for(int i=1;i<=m;i++)
{
cin >> maze[i].l >> maze[i].r;
maze[i].id=i;
}
sort(maze+1,maze+m+1,cmp);
l=1;
r=0;
ans=0;
for(int i=1;i<=m;i++){
while(r<maze[i].r){
r++;
pls(r);
}
while(r>maze[i].r){
min(r);
r--;
}
while(l<maze[i].l){
min(l);
l++;
}
while(l>maze[i].l){
l--;
pls(l);
}
if(maze[i].l==maze[i].r)
{
maze[i].a=0;
maze[i].b=1;
continue;
}
maze[i].a=ans-(maze[i].r-maze[i].l+1);
maze[i].b=(maze[i].r-maze[i].l+1)*1LL*(maze[i].r-maze[i].l);
ll gcdd=gcd(maze[i].a,maze[i].b);
maze[i].a/=gcdd;
maze[i].b/=gcdd;
}
sort(maze+1,maze+m+1,cmpp);
for(int i=1;i<=m;i++)
cout << maze[i].a << '/' << maze[i].b << endl;
return 0;
}