当前位置:编程学习 > C/C++ >>

SPOJ 1182. Sorted bit squence (数位统计+二分)

题目:将区间内的数,按照二进制中1的个数升序排列,个数相同的按大小升序排列。求区间内第K个数。
http://www.spoj.pl/problems/SORTBIT/
关于数位统计类问题可以看论文 《浅谈数位类统计问题》
首先可以根据前一道题所学的,枚举1的个数,然后找到区间内含有若干个1的数量,最终得到第K个数包含几个1。
这样就确定出了答案中包含了Len个1。
然后在区间[l,r]内二分答案,查找[l,mid]中包含Len个1的个数,由些二分。
麻烦的时候题目中还有负数,负数是按照其补码计算。
不过题目说了同正同负,那么对于同正的没有问题,对于同负的。
最高位都为1,我们先把最高位的1去掉,就转化成了正数,然后再进行统计,最后输出的时候把最高位加上即可。
不过注意0的情况,特判!!!
[cpp] 
#include<iostream> 
#include<cstring> 
#include<queue> 
#include<cstdio> 
#include<cmath> 
#include<algorithm> 
#define N 30 
#define inf 1<<29 
#define MOD 2007 
#define LL long long 
using namespace std; 
int c[35][35]={0}; 
//统计[0,n]中包含k个1的数量 
int slove(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((1<<(i-1))<=n) 
            sum+=c[i-1][k-tot]; 
    } 
    if(tot+n==k)  sum++; 
    return sum; 

int calc(int l,int r,int k){ 
    int len=1; 
    for(int i=1;i<=31;i++){ 
        int now=slove(r,i)-slove(l-1,i); 
        if(k<=now)  break; 
        k-=now; 
        len=i+1; 
    } 
    int low=l,high=r,mid; 
    while(low<high){ 
        //二分答案,然后查找[l,mid]中包含len个1的数量 
        mid=(int)(((LL)low+(LL)high)/2); 
        int now=slove(mid,len)-slove(l-1,len); 
        if(now<k) 
            low=mid+1; 
        else 
            high=mid; 
    } 
    return low; 

int main(){ 
    int t,l,r,k; 
    for(int i=0;i<=32;i++){ 
        c[i][0]=c[i][i]=1; 
        for(int j=1;j<i;j++) 
            c[i][j]=c[i-1][j-1]+c[i-1][j]; 
    } 
    scanf("%d",&t); 
    while(t--){ 
        scanf("%d%d%d",&l,&r,&k); 
        if(l==0&&r==0){ 
            printf("0\n"); 
            continue; 
        } 
        if(l>=0&&r>=0){ 
            if(l==0){ 
                k--; 
                l=1; 
            } 
            if(k==0){ 
                printf("0\n"); 
                continue; 
            } 
            printf("%d\n",calc(l,r,k)); 
        } 
        else{ 
            if(r==0){ 
                k--; 
                r=-1; 
            } 
            //去掉最高位 
            l&=(~(1<<31)); 
            r&=(~(1<<31)); 
            cout<<l<<" "<<r<<endl; 
            printf("%d\n",(1<<31)|calc(l,r,k)); 
        } 
    } 
    return 0; 

作者:ACM_cxlove
补充:软件开发 , C++ ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,