BZOJ P2038 [2009国家集训队] 小Z的袜子【莫队】

首先让我们考虑一下答案的表达式。

设当前的询问区间为 [ L e f t , R i g h t ] ,且在当前区间中第 i 种袜子有 N u m [ i ] 支,那么

A n s = C N u m [ 1 ] 2 + C N u m [ 2 ] 2 + C N u m [ 3 ] + . . . 2 C R i g h t + 1 L e f t 2

L e n g t h = R i g h t + 1 L e f t
展开组合数:
A n s = N u m [ 1 ] 2 + N u m [ 2 ] 2 + N u m [ 3 ] 2 + . . . L e n g t h L e n g t h ( L e n g t h 1 )

于是我们先的任务就是求得当前区间的 N u m [ i ] 即可,莫队搞一搞,注意特判与最后的分数化为最简。

参考代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define SG string
#define DB double
#define LL long long
using namespace std;
const LL Max=5e4+5;
struct Node{
    LL X,Y,Id;
}Ask[Max];
LL N,M,S,Tot=1ll,A[Max],B[Max],Cnt[Max],Ans_X[Max],Ans_Y[Max];
inline LL Read(){
    LL X=0;char CH=getchar();bool F=0;
    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 F?-X:X;
}
inline void Write(LL X){
    if(X<0)X=-X,putchar('-');
    if(X>9)Write(X/10);
    putchar(X%10+48);
}
bool Cmp(Node P,Node Q){
    return B[P.X]==B[Q.X]?P.Y<Q.Y:B[P.X]<B[Q.X];
}
LL GCD(LL X,LL Y){
    while(Y^=X^=Y^=X%=Y);
    return X;
}
void Insert(LL X){
    Tot-=Cnt[X]*Cnt[X];++Cnt[X];Tot+=Cnt[X]*Cnt[X];
}
void Delete(LL X){
    Tot-=Cnt[X]*Cnt[X];--Cnt[X];Tot+=Cnt[X]*Cnt[X];
}
int main(){
    LL I,J,K;
    N=Read(),M=Read();S=sqrt(N);
    for(I=1;I<=N;I++){
        A[I]=Read();
        B[I]=I/S;
    }
    for(I=1;I<=M;I++){
        Ask[I].Id=I;
        Ask[I].X=Read();
        Ask[I].Y=Read();
    }
    sort(Ask+1,Ask+1+M,Cmp);
    LL Left=1ll,Right=1ll;++Cnt[A[1]];
    for(I=1;I<=M;I++){
        if(Ask[I].X==Ask[I].Y){
            Ans_X[Ask[I].Id]=0;
            Ans_Y[Ask[I].Id]=1;continue;
        }
        while(Right<Ask[I].Y){
            Insert(A[++Right]);
        }
        while(Right>Ask[I].Y){
            Delete(A[Right--]);
        }
        while(Left<Ask[I].X){
            Delete(A[Left++]);
        }
        while(Left>Ask[I].X){
            Insert(A[--Left]);
        }
        LL Length=Ask[I].Y+1-Ask[I].X;
        Ans_X[Ask[I].Id]=Tot-Length;
        Ans_Y[Ask[I].Id]=Length*(Length-1);
        LL _GCD=GCD(Ans_X[Ask[I].Id],Ans_Y[Ask[I].Id]);
        Ans_X[Ask[I].Id]/=_GCD;
        Ans_Y[Ask[I].Id]/=_GCD;
    }
    for(I=1;I<=M;I++){
        Write(Ans_X[I]),putchar('/'),Write(Ans_Y[I]),putchar('\n');
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yanzhenhuai/article/details/81144150