P1494 [国家集训队]小Z的袜子

P1494 [国家集训队]小Z的袜子

发现这道题没有修改,并且可以离线,于是可以考虑莫队。

那么具体这么做?很容易发现答案就是这个区间所有颜色个数 \(d_i*(d_i-1)\) 的和再除以 \(r-l\)\(r-l-1\) 即可。

于是我们莫队只需要维护一下分子的平方项,另外一个我们可以直接得到:\(\sum_{i=1}^{n}{d_i}=r-l+1\)

那么最后直接约分即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=100005,M=1000005;
#define ll long long
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-'){f=-1;}ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    return x*f;
}
int a[N],pos[N],n,m;
ll ANS[N][2],ans,cnt[N];
struct node{
    int l,r,id;
}q[N];
inline bool cmp(node x,node y){
    if(pos[x.l]==pos[y.l]) return x.r<y.r;
    return pos[x.l]<pos[y.l];
}
inline void update(int id,int f){
    int x=a[id];
    ans-=cnt[x]*(cnt[x]-1);
    cnt[a[id]]+=f;
    ans+=cnt[x]*(cnt[x]-1);
    return ;
}
int main(){
    n=read(),m=read();
    int op=sqrt(n);
    for(int i=1;i<=n;i++){
        a[i]=read();
        pos[i]=i/op;
    }
    for(int i=1;i<=m;i++){
        q[i].l=read(),q[i].r=read(),q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);
    for(int i=1,l=1,r=0;i<=m;i++){
        while(l<q[i].l) update(l++,-1);
        while(l>q[i].l) update(--l,1);
        while(r<q[i].r) update(++r,1);
        while(r>q[i].r) update(r--,-1);
        if(q[i].l==q[i].r){
            ANS[q[i].id][0]=0;
            ANS[q[i].id][1]=1;
            continue;
        }
        ll len=q[i].r-q[i].l+1;
        ll d=__gcd(ans,len*(len-1));
        ANS[q[i].id][0]=ans/d;
        ANS[q[i].id][1]=len*(len-1)/d;

    }
    for(int i=1;i<=m;i++) printf("%lld/%lld\n",ANS[i][0],ANS[i][1]);
    return 0;
}

posted @ 2021-04-13 14:56  __Anchor  阅读(41)  评论(0编辑  收藏  举报