BZOJ-2038: [2009国家集训队]小Z的袜子(hose)(莫队)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std ;
#define ll long long
#define MAXN 50010
#define MAXM 50010
ll gcd( ll x , ll y ) {
    if ( x < y ) swap( x , y ) ;
    while ( y ) {
        ll k = y ;
        y = x % y ;
        x = k ;
    }
    return x ;
}
int n , N ;
struct query {
    int l , r , t ;
    bool operator < ( const query &a ) const {
        return ( l / N ) < ( a.l / N ) || ( ( l / N ) == ( a.l / N ) && r < a.r ) ;
    }
} q[ MAXM ] ;
ll Ans[ MAXM ][ 2 ] ;
int m , c[ MAXN ] , cnt[ MAXN ] ;
int main(  ) {
    scanf( "%d%d" , &n , &m ) ;
    N = int( sqrt( n ) ) ;
    for ( int i = 0 ; i ++ < n ; ) scanf( "%d" , c + i ) ;
    for ( int i = 0 ; i ++ < m ; ) {
        scanf( "%d%d" , &q[ i ].l , &q[ i ].r ) ;
        q[ i ].t = i ;
    }
    sort( q + 1 , q + m + 1 ) ;
    ll rec ;
    for ( int i = 0 , l , r ; i ++ < m ; ) {
        if ( i == 1 || q[ i ].l / N != q[ i - 1 ].l / N ) {
            for ( int j = 0 ; j <= n ; ++ j ) cnt[ j ] = 0 ;
            l = q[ i ].l , r = q[ i ].r ;
            for ( int j = l ; j <= r ; ++ j ) ++ cnt[ c[ j ] ] ;
            rec = 0 ;
            for ( int j = 0 ; j <= n ; ++ j ) {
                rec += ( ll )( cnt[ j ] ) * ( ll )( cnt[ j ] - 1 ) ;
            }
        }
        for ( ; r < q[ i ].r ; ++ r ) {
            int s = c[ r + 1 ] ;
            rec -= ( ll )( cnt[ s ] ) * ( ll )( cnt[ s ] - 1 ) ;
            ++ cnt[ s ] ;
            rec += ( ll )( cnt[ s ] ) * ( ll )( cnt[ s ] - 1 ) ;
        }
        for ( ; l < q[ i ].l ; ++ l ) {
            int s = c[ l ] ;
            rec -= ( ll )( cnt[ s ] ) * ( ll )( cnt[ s ] - 1 ) ;
            -- cnt[ s ] ;
            rec += ( ll )( cnt[ s ] ) * ( ll )( cnt[ s ] - 1 ) ;
        }
        for ( ; l > q[ i ].l ; -- l ) {
            int s = c[ l - 1 ] ;
            rec -= ( ll )( cnt[ s ] ) * ( ll )( cnt[ s ] - 1 ) ;
            ++ cnt[ s ] ;
            rec += ( ll )( cnt[ s ] ) * ( ll )( cnt[ s ] - 1 ) ;
        }
        if ( rec ) {
            ll ret = gcd( rec , ( ll )( r - l + 1 ) * ( ll )( r - l ) ) ;
            Ans[ q[ i ].t ][ 0 ] = rec / ret , Ans[ q[ i ].t ][ 1 ] = ( ( ll )( r - l + 1 ) * ( ll )( r - l ) ) / ret ;
        } else Ans[ q[ i ].t ][ 0 ] = 0 , Ans[ q[ i ].t ][ 1 ] = 1 ;
    }
    for ( int i = 0 ; i ++ < m ; ) printf( "%lld/%lld\n" , Ans[ i ][ 0 ] , Ans[ i ][ 1 ] ) ;
    return 0 ;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值