题意:给出一个非降序的数组,给出Q个询问,每个询问给出起点和终点,问在这个区间中出现频率最多的数字的次数。
思路:这题可以用线段树,不过最近在学RMQ,所以用ST做的。这题的难点在于初始化,初始化后直接套模板就行了,来说说初始化吧。
一个区间会出现三种情况:
1、1111111111111,整个区间都被同一个数字占据,那么直接返回(r-l+1)就行了,
2、1111122222222,整个区间只由开始和结尾两种数字组成,这种情况返回两者中较大的。
3、11111222233333,区间中除了两头的数字还有其他数字,那么就用ST求出最大值就行了。
对于每个数字出现的次数,用两个数组来存,一个数组存到目前为止这个数字出现了几次,另一个数组存这个数字总共出现了几次。呃,讲的不是很清楚,可以看代码。
View Code
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <algorithm> #include <math.h> #include <queue> #define N 100004 using namespace std ; int a[N] , b[N] , mx[N][22] , dat[N] ; int n , q ; int maxs ( int x , int y ) { return x > y ? x : y ; } void init() { int i , j , m ; m = floor( log( (double)n ) / log( 2.0)); for ( i = 1 ; i <= n ; i++ ) mx[i][0] = a[i] ; for ( i = 1 ; i <= m ; i++ ) { for( j = 1 ; j + ( 1<<(i-1)) - 1 <= n ; j++ ) mx[j][i] = maxs( mx[j][i-1] , mx[j+(1<<(i-1))][i-1] ) ; } } int find( int l , int r ) { if ( a[r] >= ( r - l + 1 )) return ( r - l + 1); int m = maxs( b[l] - a[l] + 1 , a[r] ); int k = 0 ; l = l + b[l] - a[l] + 1; r = r - a[r] ; if ( l > r ) return m ; while( l + ( 1<<k ) < r - ( 1<<k ) +1 ) ++k; return maxs( m , maxs( mx[l][k] , mx[r-(1<<k)+1][k] )); } int main() { int i , s , e ; while( scanf( "%d" , &n ) != EOF ) { if( n == 0 ) break ; scanf( "%d" , &q ); for( i = 1 ; i <= n ; i++ ) { scanf( "%d" , &dat[i] ); a[i] = 1 ; } for( i = 2 ; i <= n ; i++ ) { if( dat[i] == dat[i-1] ) a[i] = a[i-1] + 1; } b[n] = a[n] ; for ( i = n - 1 ; i >= 1 ; i-- ) { if ( dat[i] == dat[i+1] ) b[i] = b[i+1] ; else b[i] = a[i] ; } init(); while( q-- ) { scanf( "%d%d" , &s , &e ); printf( "%d\n" , find( s , e )); } } return 0 ; }