#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<set>
#include<queue>
#include<vector>
#include<string>
#include<cstring>
#include<bitset>
#include<map>
#define mp make_pair
#define pb push_back
#define ll long long
using namespace std;
const int maxn=5e5+7;
const int maxs=3e5+5;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
ll sqr(ll x)
{
return x*x;
}
int n,m,k;
int a[maxn];
int val[maxn],pos[maxn];
int block;
ll ans;
struct node
{
int l,r,id;
ll a,b;
}nod[maxn];
bool cmp1(node a,node b){if(pos[a.l]==pos[b.l])return a.r<b.r;return a.l<b.l; }
bool cmp2(node a,node b){return a.id<b.id;}
void update(int x,int vs)
{
ans-=sqr(val[a[x]]);
val[a[x]]+=vs;
ans+=sqr(val[a[x]]);
}
int main()
{
scanf("%d%d",&n,&m);
ans=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=0;i<m;i++)
{
scanf("%d%d",&nod[i].l,&nod[i].r);
nod[i].id=i;
}
block=sqrt(n);
for(int i=1;i<=n;i++)
{
pos[i]=(i-1)/block+1;
}
sort(nod,nod+m,cmp1);
int l=1,r=1;
update(r,1);
for(int i=0;i<m;i++)
{
while(r<nod[i].r)
{
update(r+1,1);
r++;
}
while(r>nod[i].r)
{
update(r,-1);
r--;
}
while(l<nod[i].l)
{
update(l,-1);
l++;
}
while(l>nod[i].l)
{
update(l-1,1);
l--;
}
if(nod[i].l==nod[i].r)
{
nod[i].a=0,nod[i].b=1;
continue;
}
nod[i].a=ans-(nod[i].r-nod[i].l+1);
nod[i].b=1ll*(nod[i].r-nod[i].l)*(nod[i].r-nod[i].l+1);
ll fs=gcd(nod[i].a,nod[i].b);
nod[i].a/=fs;
nod[i].b/=fs;
}
sort(nod,nod+m,cmp2);
for(int i=0;i<m;i++)printf("%lld/%lld\n",nod[i].a,nod[i].b);
}
常规orz&&感谢 hzwer的代码,就存一下了,确实是很暴力的算法,很好理解但是有些小细节一定要注意,那四段先后顺序无影响,但必须为1~n(这个意会就好),但是l和r如果初始都为1那么要把1-1这个区间先加进去。就这样