http://www.spoj.com/problems/SORTBIT/
此题 有点难度,说实话;首先必须看一篇论文,(浅谈 数位统计)刘聪 然后就是每次右转时 进行一次统计;
二分的时候 因为含有 len 个 1 的数量有很多,但呈现字典树上升的排列;所以可以二分;不断逼近
#include<iostream> #include<stdio.h> #include<cstring> #include<algorithm> using namespace std; int N,M,K,F[32][32]; int search( int n,int k ) { int sum = 0,total = 0; for( int i = 31; i; i-- ) { if( n&(1<<i) ) { total++; if( total > k ) break; n ^=(1<<i); } if( (1<<(i-1)) <= n ) sum += F[i-1][k-total]; } if( n + total == k ) sum++; return sum; } int b_search( long long lt,long long rt,int i,int key ) { if( rt - lt <= 4 ) { for( int j = lt; j <= rt; j++ ) if( search( j,i ) - search( N-1,i ) == key ) return j; } long long mid = ( lt+rt )/2; if( search( mid,i ) - search( N-1,i ) >= key ) return b_search( lt,mid,i,key ); else return b_search( mid,rt,i,key ); } int work( ) { int len = 0; for( int i = 0; i <= 31; i++ ) { int now = search( M,i ) - search( N-1,i ); if( now >= K ) break; len = i+1; K -= now; } return b_search( N,M,len,K ); } int main( ) { int i,j,T; F[0][0] = 1; for( i = 1; i <= 32; i++ ) { F[i][0] = F[i-1][0]; for( j = 1; j <= i; j++ ) F[i][j] = F[i-1][j] + F[i-1][j-1]; } scanf("%d",&T); while( T-- ) { scanf("%d%d%d",&N,&M,&K); if( N == 0 && M == 0 ) { printf("0\n"); continue; } bool fell = false; if( N == 0 ){ N++,K--;} if( M == 0 ){ M--,K--;} if( N < 0 ) N ^= (1<<31),fell = true; if( M < 0 ) M ^= (1<<31),fell = true; int res = work( ); if( fell ) printf("%d\n",(res^(1<<31))); else printf("%d\n", res); } return 0; }