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

  

posted on 2013-05-03 19:42  浪舟  阅读(171)  评论(0编辑  收藏  举报

导航