学习算法,就是先要学习模板题,这到题就是我入门莫队的启蒙老师
题解:
先理解莫队的思想,排过序后的莫队,时间复杂度大大降低,那么我们目前只需要离线处理区间问题即可,这题询问区间中出现对数的数量,那么我们只需要在已知区间上进行加减操作就能得到当前区间的答案,这个统计概率,只要在求出增加的对数和减少的对数在区间加上,在区间减去即可
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn=1e5+5;
ll pos[maxn],ans[maxn],a[maxn];
ll cnt[maxn],mu[maxn];
ll res;
ll gcd(ll a,ll b)
{
if(b==0)
return a;
return gcd(b,a%b);
}
struct node
{
ll l,r,k;
}q[maxn];
bool cmp(node a,node b)
{
if(pos[a.l]==pos[b.l])
return a.r<b.r;
return pos[a.l]<pos[b.l];
}
ll cal(ll x)
{
return x*(x-1)/2;
}
void add(ll i)
{
cnt[a[i]]++;
res+=cal(cnt[a[i]])-cal(cnt[a[i]]-1);
}
void sub(ll i)
{
cnt[a[i]]--;
res-=cal(cnt[a[i]]+1)-cal(cnt[a[i]]);
}
int main()
{
ll n,m;
scanf("%lld %lld",&n,&m);
ll dis=sqrt(n);
for(ll i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
pos[i]=i/dis;
}
for(ll i=0;i<m;i++)
{
scanf("%lld %lld",&q[i].l,&q[i].r);
q[i].k=i;
}
sort(q,q+m,cmp);
ll l=1,r=0;
for(ll i=0;i<m;i++)
{
while(l<q[i].l)
{
sub(l++);
}
while(r>q[i].r)
{
sub(r--);
}
while(l>q[i].l)
{
add(--l);
}
while(r<q[i].r)
{
add(++r);
}
if(l==r)
{
ans[q[i].k]=0;
mu[q[i].k]=1;
}
else
{
ll len=q[i].r-q[i].l+1;
len=(len-1)*len/2;
ans[q[i].k]=res/gcd(len,res);
mu[q[i].k]=len/gcd(len,res);
}
}
for(ll i=0;i<m;i++)
{
printf("%lld/%lld\n",ans[i],mu[i]);
}
}