动态规划----SPOJ 1182. Sorted bit squence (数位统计+二分)

//
// Created by liyuanshuo on 2017/3/22.
//


/*
 * 参考:https://wenku.baidu.com/view/d2414ffe04a1b0717fd5dda8.html
 *
 * 参考:http://blog.csdn.net/acm_cxlove/article/details/7859816
 *
 * 题目链接:http://www.spoj.pl/problems/SORTBIT/
 *
 * 题目大意:
 * 将区间[m,n]内的所有整数按照其二进制表示中1的数量从小到大排序。如果1的数量
 * 相同,则按照数的大小排序。求这个序列中的第k个数。其中,负数使用补码来表示:一个
 * 负数的二进制表示与其相反数的二进制之和恰好等于2^32。
 *
 * 例如,当m=0,n=5 时,排序后的序列如下:
 * 编号 	十进制数 		二进制表示
 * 1 	0 			0000 0000 0000 0000 0000 0000 0000 0000
 * 2 	1 			0000 0000 0000 0000 0000 0000 0000 0001
 * 3 	2 			0000 0000 0000 0000 0000 0000 0000 0010
 * 4 	4 			0000 0000 0000 0000 0000 0000 0000 0100
 * 5 	3 			0000 0000 0000 0000 0000 0000 0000 0011
 * 6 	5 			0000 0000 0000 0000 0000 0000 0000 0101
 *
 * 当m=-5,n=-2 时,排序后的序列如下:
 *
 *	编号   		十进制数         			二进制表示
 *	1            -4             1111 1111 1111 1111 1111 1111 1111 1100
 *	2            -5             1111 1111 1111 1111 1111 1111 1111 1011
 *	3            -3             1111 1111 1111 1111 1111 1111 1111 1101
 *	4            -2             1111 1111 1111 1111 1111 1111 1111 1110
 *
 
 * 输入:包含多组测试数据。第一行是一个不超过 1000 的正整数,表示测试数据数量。
 * 每组数据包含 m,n,k 三个整数。
 * 输出:对于每组数据,输出排序后的序列中第 k 个数。
 * 数据规模:m × n ≥ 0, -231 ≤ m ≤ n ≤ 231-1  ,1 ≤ k ≤ min{n − m + 1, 2 147 473 547}。
 *
 * 分析:
 * 我们首先考虑 m、n 同正的情况。
 * 由于排序的第一关键字是 1 的数量,第二关键字是数的大小,因此我们很容易确定答案 中 1 的个数:依次统计区间[m,n]内二进制表示中含 1 的数量为 0,1,2,…的数,直到累加的答 案超过
 * k,则当前值就是答案含 1 的个数,假设是 s。利用例一的算法可以解决这个问题。 同时,我们也求出了答案是第几个[m,n]中含 s 个 1 的数。因此,只需二分答案,求出[m,ans] 中含 s 个
 * 1 的数的个数进行判断即可。
 * 由于每次询问的复杂度为 O(log(n)),故二分的复杂度为 O(log2(n)),这同时也是预处理
 * 的复杂度,因此此算法较为理想。
 * m<0 的情况,也不难处理,我们只要忽略所有数的最高位,求出答案后再将最高位赋回 1 即可。或者也可以直接将负数视为 32 位无符号数,采用同正数一样的处理方法。两种方 法都需要特别处理 n=0
 * 的情况。
 *
 */
#include <iostream>

using namespace std;

int f[35][35];

int count_number_k( int n, int k )
{
	int sum = 0, tot = 0;
	for (int i = 31; i ; --i)
	{
		if ( n & (1<<i) )
		{
			tot++;
			if ( tot > k )
				break;
			n ^= (1<<i);
		}
		if( (i<<(i-1)) <= n )
			sum += f[i-1][k-tot];
	}
	return sum;
}

int get_answers( int l, int r, int k)
{
	int len = 1;
	for (int i = 1; i <= 31 ; ++i)
	{
		int tmp = count_number_k (r,i) - count_number_k (l-1, i);
		if ( k <= tmp )
			break;
		k -= tmp;
		len = i+1;
	}
	int low = l, high = r, mid;
	while ( low < high )
	{
		mid = (int)(((long long)low + (long long)high) / 2);
		int tmp = count_number_k (mid, len) - count_number_k (l-1, len);
		if ( tmp < k )
		{
			low = mid + 1;
		} else
		{
			high = mid;
		}
	}
	return low;
}
int main_sorted_by_sequence( )
{
	int t, l, r, k;
	for (int i = 0; i <= 32 ; ++i)
	{
		f[i][0] = f[i][i] = 1;
		for (int j = 1; j <i ; ++j)
		{
			f[i][j] = f[i-1][j] + f[i-1][j-1];
		}
	}
	cin>>t;
	while ( t-- )
	{
		cin>>l>>r>>k;
		if( l==0 && r==0 )
		{
			cout<<"0"<<endl;
			continue;
		}
		if( l >= 0 && r >= 0 )
		{
			if( l == 0 )
			{
				k--;
				l = 1;
			}
			if( k == 0 )
			{
				cout<<"0"<<endl;
				continue;
			}
			cout<<get_answers (l, r, k)<<endl;
		}
		else
		{
			if ( r == 0 )
			{
				k--;
				r = -1;
			}
			l &= (~(1<<31));
			r &= (~(1<<31));
			cout<<((1<<31)|get_answers (l, r, k))<<endl;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/liyuanshuo_nuc/article/details/64921400
BIT
今日推荐