Spoj 1182
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;
}
浙公网安备 33010602011771号