程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> SPOJ 1182. Sorted bit squence (數位統計+二分)

SPOJ 1182. Sorted bit squence (數位統計+二分)

編輯:C++入門知識

題目:將區間內的數,按照二進制中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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved