//
// 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;
}
动态规划----SPOJ 1182. Sorted bit squence (数位统计+二分)
猜你喜欢
转载自blog.csdn.net/liyuanshuo_nuc/article/details/64921400
今日推荐
周排行