spoj1182 Sorted bit squence
2015-08-13 22:22
477 查看
题目大意:给你一个区间[m,n],把这个区间里的数字排序,排序的规则是按照二进制1的个数从少到多排,如果个数相同,则按照大小排序。让你求第k小的数是谁
此题可利用ural1057的方法,先计算出从m到n这个区间中含有1个1的有几个,含有2个1的有几个一直到含有31个1的有几个,然后与k进行比较,看第k小的数字应该是含有几个1的,假设含有pos个1,然后从区间左端点开始二分答案,如果从区间左端点到mid含有pos个1的数小于等于k个,就让l = k + 1,否则r = k;然后再求出新的mid进行比较
AC代码
<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int f[35][35];
void init()
{
memset(f,0,sizeof(f));
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] + f[i-1][j-1];
}
}
int slove(int x, int k)
{
int tot = 0,ans = 0;
for(int i = 31; i > 0; i--)
{
if(x & (1 << i))
{
tot ++;
if(tot > k) break;
x = x^(1 << i);
}
if((1 << (i - 1)) <= x)
ans += f[i-1][k - tot];
}
if(tot + x == k) ans ++;
return ans;
}
int cal(int m,int n, int k)
{
int pos = 1;
for(int i = 1; i <= 31; i++)
{
int cnt = slove(n,i) - slove(m-1,i);
//printf("cnt%d ",cnt);
if(k <= cnt) //相等的时候也是含有i个1
{
pos = i;
break;
}
k-=cnt;
}
//printf("pos%d %d\n",pos,k);
int l = m, r = n,mid;
while(l < r)
{
mid =(int)(((long long)l + (long long)r)/2); //进行强制类型转换,两个int相加可能会超int
//printf("%d %d %d\n",l,r,mid);
int tem = slove(mid,pos) - slove(m - 1,pos);
if(tem < k)
l = mid+1;
else
r = mid;
}
return l;
}
int main()
{
init();
int t,m,n,k;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&m,&n,&k);
if(m == 0 && n == 0)
{
printf("0\n");
continue;
}
if( m >= 0 && n >= 0)
{
if(m == 0)
{
k--;
m = 1;
}
if(k == 0)
{
printf("0\n");
continue;
}
//printf("%d %d %d\n",m,n,k);
printf("%d\n",cal(m,n,k));
}
else
{
if(n == 0)
{
k--;
n = -1;
if(k == 0)
{
printf("0\n");
continue;
}
}
m &= (~(1<<31));
n &= (~(1 << 31));
printf("%d\n",(1 << 31)|cal(m,n,k));
}
}
}
</span>
此题可利用ural1057的方法,先计算出从m到n这个区间中含有1个1的有几个,含有2个1的有几个一直到含有31个1的有几个,然后与k进行比较,看第k小的数字应该是含有几个1的,假设含有pos个1,然后从区间左端点开始二分答案,如果从区间左端点到mid含有pos个1的数小于等于k个,就让l = k + 1,否则r = k;然后再求出新的mid进行比较
AC代码
<span style="font-family:KaiTi_GB2312;font-size:18px;">#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
int f[35][35];
void init()
{
memset(f,0,sizeof(f));
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] + f[i-1][j-1];
}
}
int slove(int x, int k)
{
int tot = 0,ans = 0;
for(int i = 31; i > 0; i--)
{
if(x & (1 << i))
{
tot ++;
if(tot > k) break;
x = x^(1 << i);
}
if((1 << (i - 1)) <= x)
ans += f[i-1][k - tot];
}
if(tot + x == k) ans ++;
return ans;
}
int cal(int m,int n, int k)
{
int pos = 1;
for(int i = 1; i <= 31; i++)
{
int cnt = slove(n,i) - slove(m-1,i);
//printf("cnt%d ",cnt);
if(k <= cnt) //相等的时候也是含有i个1
{
pos = i;
break;
}
k-=cnt;
}
//printf("pos%d %d\n",pos,k);
int l = m, r = n,mid;
while(l < r)
{
mid =(int)(((long long)l + (long long)r)/2); //进行强制类型转换,两个int相加可能会超int
//printf("%d %d %d\n",l,r,mid);
int tem = slove(mid,pos) - slove(m - 1,pos);
if(tem < k)
l = mid+1;
else
r = mid;
}
return l;
}
int main()
{
init();
int t,m,n,k;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&m,&n,&k);
if(m == 0 && n == 0)
{
printf("0\n");
continue;
}
if( m >= 0 && n >= 0)
{
if(m == 0)
{
k--;
m = 1;
}
if(k == 0)
{
printf("0\n");
continue;
}
//printf("%d %d %d\n",m,n,k);
printf("%d\n",cal(m,n,k));
}
else
{
if(n == 0)
{
k--;
n = -1;
if(k == 0)
{
printf("0\n");
continue;
}
}
m &= (~(1<<31));
n &= (~(1 << 31));
printf("%d\n",(1 << 31)|cal(m,n,k));
}
}
}
</span>
相关文章推荐
- ural1057 Amount of Degrees数位统计入门题
- hdu 2089 不要62 (数位DP)
- hdu 3652 B-number (数位DP)
- hdu 3555 Bomb (数位DP)
- poj 3252 Round Numbers (数位DP)
- poj 3286 How many 0's? (数位DP+ 统计)
- hdu 4734 F(x) (2013成都网络赛G题)(数位DP)
- 数位DP小结
- poj2282 The Counting Problem
- UVA 11038 How Many O's? (数位统计 )
- UIPageControl 与 UIScrollView
- Android中Looper的quit方法和quitSafely方法
- UVa 11955 I Can Guess the Data Structure!
- The Unique MST prim(次小生成树)
- 【转载】UITableView
- iOS开发 -- UILable详解
- iOS开发 -- UIView详解
- KVC(Key-value coding)机制
- UIPageViewController
- POJ 题目3481 Double Queue(SBT ro map)