二分
Posted $mathcal{Yubai}$
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分相关的知识,希望对你有一定的参考价值。
选数问题:选出集合中第\\(i\\)小的数
如果排序的话,复杂度是\\(nlogn\\)的,是因为他对一些没有用的东西也进行了操作,所以我们尽量少进行没有用的操作,有一种\\(O(n)\\)的算法
内容见\\(link\\)
复杂度证明:每次都选择一个数后,我们只用向另一半递归,所以计算次数为
\\(n+n/2+n/4+n/8+....+1\\),易知这是一个收敛的等比数列,和不会大于\\(2n\\),故复杂度是\\(O(n)\\)
所以说复杂度不能想当然\\(logn\\),还是要自己推,一般如果\\(check\\)函数的计算范围随着端点的缩小而缩小,复杂度就是\\(O(n)\\)的,如果\\(check\\)复杂度一直是\\(O(n)\\),那么就是\\(nlogn\\)
code
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <ctime>
#define int long
#define R register int
#define printf tz1=printf
using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned G ;
const int N = 5e6 + 10 ;
inline int read(){
int w = 0 ; bool fg = 0 ; char ch = getchar() ;
while( ch < \'0\' || ch > \'9\' ) fg |= ( ch == \'-\' ) , ch = getchar() ;
while( ch >= \'0\' && ch <= \'9\' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - \'0\' ) , ch = getchar() ;
return fg ? -w : w ;
}
int tz1 , n , m , a [N] ;
void sc(){
n = read() , m = read() ; m ++ ;
for( R i = 1 ; i <= n ; i ++ ) a [i] = read() ;
}
inline void debug( int l , int r ){
for( R i = l ; i <= r ; i ++ ) printf( "%ld " , a [i] ) ; puts( "" ) ;
}
inline void choose( int l , int r , int x ){
// printf( "L%ld R%ld X%ld\\n" , l , r , x ) ;
int mid = ( l + r ) >> 1 ; //懒得写随机,所以取的中点
swap( a [mid] , a [l] ) ;
int cnt = l ; //debug( l , r ) ;
for( R i = l + 1 ; i <= r ; i ++ )
if( a [i] < a [l] ) swap( a [++ cnt] , a [i] ) ;
swap( a [cnt] , a [l] ) ;
if( cnt - l == x - 1 ) { printf( "%ld\\n" , a [cnt] ) ; return ; }
if( cnt - l < x ) choose( cnt + 1 , r , x - cnt + l - 1 ) ;
else choose( l , cnt , x ) ;
}
void work(){
choose( 1 , n , m ) ;
}
signed main(){
sc() ;
work() ;
return 0 ;
}
以上是关于二分的主要内容,如果未能解决你的问题,请参考以下文章