• Round Numbers(poj 3252)


    题意:算出区间内二进制中0的个数大于等于1的个数的数字有多少个

    /*
      本来以为用数位DP搞,但是组合数更简单。
      我们设n的二进制长度为len。 
      ①:先考虑长度小于len的数字。
          这里以数字22为例,二进制拆成10110,len=5。
          len=1时,只能是1(题目要求是正数);
          len=2时,第一位是1,剩下的1位,至少有1个0,ans+=C(1,1);
          …… 
            len=k时,第一位是1,剩下的len-k位,如果至少要有p个0,那么ans+=C(len-k,p)+...+C(len-k,len-k)。
      ②:再考虑长度等于len的数字。
          第一位是1。  
          第二位是0,所以第二位不能为1,必须是0。 
          第三位为0的话,后面两位可以有1个0,2个0,ans+=C(2,1)+C(2,2)。 
          接下来把第三位恢复为1,看第四位。假如第四位是0,后面一位必须是0,ans+=C(1,1)。  
    */
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define N 51
    #define lon long long
    using namespace std;
    int c[N][N];
    void getc(){
        for(int i=1;i<N;i++)
            for(int j=0;j<=i;j++){
                if(j==0||i==j) c[i][j]=1;
                else c[i][j]=c[i-1][j]+c[i-1][j-1];
            }        
    }
    lon solve(lon n){
        if(n==1) return 0;
        lon ans=0;
        int a[N]={0},len=0;
        while(n){
            a[++len]=n%2;
            n>>=1;
        }
        reverse(a+1,a+len+1);
        for(int i=1;i<len;i++)
            for(int j=(i-1)/2+1;j<i;j++)
                ans+=(lon)c[i-1][j];
        int p0=0,p1=1;
        for(int i=2;i<len;i++){
            if(!a[i]) {p0++;continue;}
            for(int j=len-i;2*j+p0+1>=p1+len-i;j--)
                ans+=(lon)c[len-i][j];
            p1++;
        }
        if(a[len]&&p0+1>=p1) ans++;
        return ans;
    }
    int main(){
        getc();
        lon a,b;
        cin>>a>>b;
        cout<<solve(b+1)-solve(a);
        return 0;
    }
     
  • 相关阅读:
    linux curses函数库
    在Android library中不能使用switch-case语句访问资源ID的原因分析及解决方案
    Android Support ;v4、v7、v13的区别
    background-position
    java web 之 web.xml篇
    javaweb之Cookie篇
    Enumeration 接口
    Java Bad version number in .class file
    使用AppCan自带的升级功能实现移动端升级
    obj.offsetHeight与obj.style.height区别
  • 原文地址:https://www.cnblogs.com/harden/p/6288028.html
Copyright © 2020-2023  润新知