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