信息学竞赛题解(IO题解)

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

2018-11-13  本文已影响0人  AmadeusChan

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2038

作为一个GDKOI被虐了之后才滚过来学莫队的蒟蒻,我就不想吐槽自己什么了,明明可以早一天看就可以多水40分的说。。。

莫队其实听好写的,对l分块,然后按r排序,然后直接转移即可,这样的复杂度明显是O(n^(3/2))。

代码:

#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 ;

}


上一篇 下一篇

猜你喜欢

热点阅读