spoj1182Sorted bit squence【数位dp】
2016-02-17 14:52
459 查看
Description
Let's consider the 32 bit representation of all integers i from m up to n inclusive (m ≤ i ≤ n; m × n ≥ 0, -2^31 ≤ m ≤ n ≤ 2^31-1). Note that a negative number is represented in 32 bit Additional Code. That is the 32 bit sequence, the binary
sum of which and the 32 bit representation of the corresponding positive number is 2^32 (1 0000 0000 0000 0000 0000 0000 0000 0000 in binary).
For example, the 32 bit representation of 6 is 0000 0000 0000 0000 0000 0000 0000 0110
and the 32 bit representation of -6 is 1111 1111 1111 1111 1111 1111 1111 1010
because
0000 0000 0000 0000 0000 0000 0000 0110 (6)
+
1111 1111 1111 1111 1111 1111 1111 1010 (-6)
-------------------------------------------------
= 1 0000 0000 0000 0000 0000 0000 0000 0000 (2^32)
Let's sort the 32 bit representations of these numbers in increasing order of the number of bit 1. If two 32 bit representations that have the same number of bit 1, they are sorted in lexicographical order.
For example, with m = 0 and n = 5, the result of the sorting will be
with m = -5 and n = -2, the result of the sorting will be
Given m, n and k (1 ≤ k ≤ min{n − m + 1, 2 147 473 547}), your task is to write a program to find a number corresponding to k-th representation in the sorted sequence.
For each data set, the only line contains 3 integers m, n and k separated by space.
各种不应该的错误==忘记初始化,前后不对应,T^T卡了一天啊
我们首先考虑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 即/**********************
spoj1182
2016.2.17
3379 0
C++ (g++ 4.9.2)
1526
2016-02-17 14:42:14
**********************/
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,k,f[33][33];
void init()
{
f[0][0]=1;
for(int i=1;i<=32;i++)
{
f[i][0]=f[i-1][0];
for(int j=1;j<=i;j++) f[i][j]=f[i-1][j-1]+f[i-1][j];
}
}
int cal(int x,int k)
{
int sum=0,tot=0,pos=0;
int bit[33];
memset(bit,0,sizeof(bit));
while(x)
{
bit[++pos]=x%2;
x/=2;
}
for(int i=pos;i>=1;i--)
{
if(!bit[i]) continue;
sum+=f[i-1][k-tot];
tot++;
if(tot>=k) break;
}
if(tot==k) sum++;
return sum;
}
int fnd(int l,int r,int k)
{
int i,num;
for(i=1;i<=31;i++)
{
num=cal(r,i)-cal(l-1,i);
if(num>=k) break;
else k-=num;
}
int tmp=l;
while(l<=r)
{
int mid=l+(r-l)/2;
num=cal(mid,i)-cal(tmp-1,i);
if(num>=k) r=mid-1;
else l=mid+1;
}
return l;
}
int main()
{
// freopen("cin.txt","r",stdin);
int t;
init();
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&m,&n,&k);
if(m<0)
{
m&=~(1<<31);
if(n==0)
{
n--;
k--;
}
n&=~(1<<31);
// printf("m=%d n=%d\n",m,n);
printf("%d\n",(1<<31)|fnd(m,n,k));
}
else
{
if(m==0) k--,m++;
printf("%d\n",fnd(m,n,k));
}
}
return 0;
}
Let's consider the 32 bit representation of all integers i from m up to n inclusive (m ≤ i ≤ n; m × n ≥ 0, -2^31 ≤ m ≤ n ≤ 2^31-1). Note that a negative number is represented in 32 bit Additional Code. That is the 32 bit sequence, the binary
sum of which and the 32 bit representation of the corresponding positive number is 2^32 (1 0000 0000 0000 0000 0000 0000 0000 0000 in binary).
For example, the 32 bit representation of 6 is 0000 0000 0000 0000 0000 0000 0000 0110
and the 32 bit representation of -6 is 1111 1111 1111 1111 1111 1111 1111 1010
because
0000 0000 0000 0000 0000 0000 0000 0110 (6)
+
1111 1111 1111 1111 1111 1111 1111 1010 (-6)
-------------------------------------------------
= 1 0000 0000 0000 0000 0000 0000 0000 0000 (2^32)
Let's sort the 32 bit representations of these numbers in increasing order of the number of bit 1. If two 32 bit representations that have the same number of bit 1, they are sorted in lexicographical order.
For example, with m = 0 and n = 5, the result of the sorting will be
No. | Decimal number | Binary 32 bit representation |
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 |
No. | Decimal number | Binary 32 bit representation |
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 |
Input
The input consists of several data sets. The first line of the input file contains the number of data sets which is a positive integer and is not bigger than 1000. The following lines describe the data sets.For each data set, the only line contains 3 integers m, n and k separated by space.
Output
For each data set, write in one line the k-th number of the sorted numbers.Example
Sample input: 2 0 5 3 -5 -2 2 Sample output: 2 -5
各种不应该的错误==忘记初始化,前后不对应,T^T卡了一天啊
我们首先考虑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 即/**********************
spoj1182
2016.2.17
3379 0
C++ (g++ 4.9.2)
1526
2016-02-17 14:42:14
**********************/
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,k,f[33][33];
void init()
{
f[0][0]=1;
for(int i=1;i<=32;i++)
{
f[i][0]=f[i-1][0];
for(int j=1;j<=i;j++) f[i][j]=f[i-1][j-1]+f[i-1][j];
}
}
int cal(int x,int k)
{
int sum=0,tot=0,pos=0;
int bit[33];
memset(bit,0,sizeof(bit));
while(x)
{
bit[++pos]=x%2;
x/=2;
}
for(int i=pos;i>=1;i--)
{
if(!bit[i]) continue;
sum+=f[i-1][k-tot];
tot++;
if(tot>=k) break;
}
if(tot==k) sum++;
return sum;
}
int fnd(int l,int r,int k)
{
int i,num;
for(i=1;i<=31;i++)
{
num=cal(r,i)-cal(l-1,i);
if(num>=k) break;
else k-=num;
}
int tmp=l;
while(l<=r)
{
int mid=l+(r-l)/2;
num=cal(mid,i)-cal(tmp-1,i);
if(num>=k) r=mid-1;
else l=mid+1;
}
return l;
}
int main()
{
// freopen("cin.txt","r",stdin);
int t;
init();
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&m,&n,&k);
if(m<0)
{
m&=~(1<<31);
if(n==0)
{
n--;
k--;
}
n&=~(1<<31);
// printf("m=%d n=%d\n",m,n);
printf("%d\n",(1<<31)|fnd(m,n,k));
}
else
{
if(m==0) k--,m++;
printf("%d\n",fnd(m,n,k));
}
}
return 0;
}
相关文章推荐
- UITableViewCell左右侧滑动出现多个按钮
- CoreBluetooth - 中心模式
- UITableViewCell分割线左侧不能到达边缘的解决方案
- iOSUIBezierPath
- UIImagePickerController使用小结
- UIView的bounds和frame学习
- error :Java.exe finished with non-zero exit value 1(或2)
- 关于FineUI使用问题的一点记录。
- FrexibleSearch Query语法
- IOS中Key-Value Coding (KVC)的使用具体解释
- onInterceptTouchEvent dispatchTouchEvent requestDisallowInterceptTouchEvent
- UINavgationController
- AndroidStudioTutorial_160217S001_简单UI
- UIControlEvent
- UICollectionView实现无限轮播
- iOS 解决页面按钮同时点击,同时触发问题 设置所有UIButton的ExclusiveTouch属性为YES
- HDU 1159:Common Subsequence
- java建造者模式(Builder)
- UIToolBar的使用
- 学习UITextField忽略掉的细节