SPOJ 1182 Sorted bit squence

题目链接:http://www.spoj.com/problems/SORTBIT/

题意:给出[L,R],已知L*R>=0。将该区间的数字按照二进制中1的个数升序排序,1的个数相等按照数字的大小升序排序。求排序后的数字中第K个数字?

思路:我们首先看0<=L<=R的情况。首先肯定是枚举含有1、2、3……个1的个数,直到枚举到x个1的个数大于K。然后再二分ans,计算[L,ans]中含有x个1的个数。

然后看负数情况。

SPOJ 1182 Sorted bit squence

我们发现,可以去掉最高位的1,变成正数。计算之后再加上最高位的1.

i64 C[N][N];



void init()

{

    C[0][0]=1;

    int i,j;

    for(i=1;i<N;i++)

    {

        C[i][0]=C[i][i]=1;

        for(j=1;j<i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j];

    }

}



int L,R,K;



int get(int n,int k)

{

    int ans=0,i,cnt=0;

    for(i=31;i>=1;i--)

    {

        if(n&(1<<i))

        {

            cnt++;

            if(cnt>k) break;

            n^=(1<<i);

        }

        if((1<<(i-1))<=n) ans+=C[i-1][k-cnt];

    }

    if(n+cnt==k) ans++;

    return ans;

}



int cal(int L,int R,int K)

{

    int i,cnt=0;

    for(i=1;i<=31;i++)

    {

        cnt=get(R,i)-get(L-1,i);

        if(K<=cnt) break;

        K-=cnt;

    }

    int low=L,high=R,M,ans;

    while(low<=high)

    {

        M=((i64)low+high)>>1;

        if(get(M,i)-get(L-1,i)<K) low=M+1;

        else ans=M,high=M-1;

    }

    return ans;

}



int main()

{

    init();

    rush()

    {

        RD(L,R,K);

        if(L==0&&R==0) puts("0");

        else if(L==0)

        {

            L=1; K--;

            if(K==0) puts("0");

            else PR(cal(L,R,K));

        }

        else if(L>0) PR(cal(L,R,K));

        else if(R==0)

        {

            R=-1; K--;

            if(K==0) puts("0");

            else PR((1<<31)|cal(L,R,K));

        }

        else PR((1<<31)|cal(L,R,K));

    }

}

  

你可能感兴趣的:(sort)