zoukankan      html  css  js  c++  java
  • POJ3252-RoundNumbers-排列组合

    当一个数的二进制表示中,0的个数大于或等于1的个数时,叫做RoundNumber。求从S到F两个数(包含)之间的RoundNumber个数。

    这类题一般都是先求出0到N的个数,然后两个相减。

    由于题目是考虑二进制中01的个数,当位数固定时,很方便计算。于是从位数方面解决问题。

    设N表示成二进制的位数为len。把0到N分为两部分。

      -位数为[0,len-1]时,可以通过简单的排列组合计算出结果。

      -位数为len时,逐位进行分析。假设N是24,表示成二进制是1 1000,1的个数是2,len/2 =2。

       最高位一定是1,否则就不是len位了。

       第二位是1,如果第二位是0,则后面的三位可以有一个1,也可以没有1,RoundNumber就是C31 +C30 个。

       后面的位都是0,这时不能将其替换成1,从0变成1将会比N更大。

    于是分两步就求助了0-N的个数。

    中间有两个小问题。一个是组合数的计算,我是从kuangbin那里抄的递推写法。关于组合数的计算还要再学习一个,最近数学专题。。。

    还有就是边界问题。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    unsigned int S,F;
    int C[33][33];
    
    void init()
    {
        C[0][0]=1;
        C[1][0]=1;C[1][1]=1;
        for(int i=2;i<33;i++)
        {
            C[i][0]=1;
            for(int j=1;j<i;j++)
              C[i][j]=C[i-1][j-1]+C[i-1][j];
            C[i][i]=1;
        }
    }
    
    
    int getbit(unsigned int x)
    {
        for(int i=31;i>=0;i--)
        {
            if(x&(1<<i)) return i+1;
        }
    }
    
    int get1(unsigned int x)
    {
        int ans = 0;
        for(int i=31;i>=0;i--)
        {
            if(x&(1<<i)) ans++;
        }
        return ans;
    }
    
    
    unsigned int get0To1(unsigned int x)
    {
        int n = getbit(x);
        int ans = 0;
        n--;
        for(int i=1;i<=n;i++)
        {
            if(i == 1) continue;
            int mx = i/2;
            for(int j=0;j<mx;j++)
            {
                ans += C[i-1][j];
            }
        }
        return ans;
    }
    
    int get0(unsigned int x)
    {
        int ans =0;
        if(x == 0) return 0;
        for(int i=0;i<32;i++)
        {
            if((x&(1<<i)) == 0) ans++;
            else return ans;
        }
        return ans;
    }
    
    unsigned int get1ToX(unsigned int x)
    {
        int one = get1(x),n=getbit(x);
        int mx = n/2,ans=0,cur=1;
        //printf("x=%d one=%d n=%d
    ",x,one,n);
        if(one <= mx) ans++;
        for(int i=n-2;i>=0;i--)
        {
            if((x&(1<<i)) == 0)
            {
                //printf("gg");
                continue;
            }
            else
            {
                for(int j=0;j<=mx-cur;j++)
                {
                    ans += C[i][j];
                }
                cur++;
            }
        }
        return ans;
    }
    
    int main()
    {
        init();
        while(~scanf("%d%d",&S,&F))
        {
            if(S > F) swap(S,F);
            //printf("all1 S=%d F=%d
    ",get0To1(S),get0To1(F));
            //printf("toX S=%d F=%d
    ",get1ToX(S),get1ToX(F));
            int ans = (get0To1(F)+get1ToX(F)) - (get0To1(S)+get1ToX(S));
            if(get1(S) <= getbit(S)/2) ans++;
            printf("%d
    ",ans);
    
        }
    }

    还有就是边界问题了。

  • 相关阅读:
    微软职位内部推荐-SENIOR SDE
    微软职位内部推荐-Senior Network Engineer
    微软职位内部推荐-Principal Dev Manager
    微软职位内部推荐-SDE II
    微软职位内部推荐-Sr DEV
    【转载】NIO服务端序列图
    【转载】NIO客户端序列图
    同步与异步
    Linux查找命令
    Spring中Bean的实例化
  • 原文地址:https://www.cnblogs.com/helica/p/5167896.html
Copyright © 2011-2022 走看看