• poj3252(组合数)


    题目链接:http://poj.org/problem?id=3252

    题目意思:给出两个整数s,f,问区间[s,f]中 "round number"的个数。(1<=s<f<=2000000000)

     "round number"定义:二进制中0的个数大于等于1的个数。

    代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #define inf 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    int c[33][33]={0};
    
    void init()//组合数打表
    {
        c[0][0]=1;
        for(int i=1;i<33;i++)
        {
            c[i][0]=1;
            for(int j=1;j<=i;j++)
                c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
    }
    
    int count(int n)//寻找比n小符合条件个数 
    {
        int d=0,zero=0,res=0;
        bool m[33]={0};
        while(n)// 转化为二进制,d计算 位数,m[]存每一位是0还是1
        {
            m[++d]=n%2;
            n/=2;
        }
        for(int i=2;i<d;i++)//计算二进制位数小于d的情况,(省略了位数为1,因为1不符合条件)
        {
            for(int j=(i+1)/2;j<i;j++)
                res+=c[i-1][j];
        }
        for(int i=d-1;i>=1;i--)//计算二进制位数等于于d的情况
        {
            if(m[i])
            {
                for(int j=(d+1)/2-(zero+1);j<i;j++)//遍历每种小于的情况 
                    res+=c[i-1][j];
            }
            else
                zero++;
        }
        return res;
    }
    
    int main()
    {
        int s,e;
        init();
        while(cin>>s>>e)
        {
            cout<<count(e+1)-count(s)<<endl;
        }
        return 0;
    }
    View Code

    思路:区间问题,容易想到写个函数找到1~n的符合条件的数量,这样用1~f中的个数减去1~s中的个数就是答案。

    因为这里写的函数  count(int n)   是找到比n小的 "round number"有多少个。所以是用count(f+1)-count(s),搞清楚区间闭合关系。

    下面就是找 "round number"的工作了:

    我们会发现当数字转为二进制时,位数小于该数的十进制一定比它小(这是肯定的,废话一句),那么可以分成两部分:

    一、二进制位数小于时

    二、二进制位数相同时

    情况一:符合条件我们需要以下几点:

    1、首位一定要是1,(怎么可能不是。。。)

    2、0的个数是位数的一半以上,包括一半。

    比如:位数是n时,那我们考虑n-1低位必须取一半及以上((n+1)/2)个0。

    选择的方式自然就想到组合数,即从n-1个(除掉首位一定是1)选(n+1)/2 ~ n-1的0有多少种情况。

    代码:

    void init()//组合数打表 
    {
        c[0][0]=1;
        for(int i=1;i<33;i++)
        {
            c[i][0]=1;
            for(int j=1;j<=i;j++)
                c[i][j]=c[i-1][j]+c[i-1][j-1];
        }
    }
    
    while(n)// 转化为二进制,d计算 位数,m[]存每一位是0还是1 
    {
        m[++d]=n%2;
        n/=2;
    }
    
    for(int i=2;i<d;i++)//计算二进制位数小于d的情况,(省略了位数为1,因为1不符合条件) 
    {
        for(int j=(i+1)/2;j<i;j++)
            res+=c[i-1][j];
    }

    情况二:计算相同位数时,因为函数  count (int n)  计算的是小于n有多少个。

    即找出二进制每一位为1时,变成0(即小于它)的情况找出。(当然第一位除外,变成0就不是d位数的二进制了,变成d-1位)

    举例:二进制  11011  

    1)   确定第二位是1         11011                 10 xxx(一定比它小)   c[3][2]+c[3][3](即剩下不确定的三位要二个0或三个0,这样0的个数才大于1)

    2)   确定第四位是1         11011                 1001x       c[1][1]一定要是0才可以

    3)   确定第五位是1         11011               已经找不到了(所以说这个函数是找到比11011小的符合条件的个数)

    很明显这也是一个组合数,必须确保0比1多的,要用一个变量zero记录确定这位之前0的个数,那么剩下的0的个数为

    (n+1)/2-(zero+1)到未确定位数,为什么减(zero+1),是确定这位要变成0.

    代码:

    for(int i=d-1;i>=1;i--)//计算二进制位数等于于d的情况
        {
            if(m[i])
            {
                for(int j=(d+1)/2-(zero+1);j<i;j++)//遍历每种小于的情况 
                    res+=c[i-1][j];
            }
            else
                zero++;
        }

     

  • 相关阅读:
    Spring异常重试框架Spring Retry
    Ubuntu 16.04无法在WPS中输入中文的问题解决
    Ubuntu 16.04使用百度云的方案
    Ubuntu 16.04安装Wine版的迅雷+QQ(完美方案,终极解决方法)
    Ubuntu下Deb软件包相关安装与卸载
    Spring在Java Filter注入Bean为Null的问题解决
    MyBatis 3在Insert之后返回主键
    MySQL JDBC URL参数(转)
    MySQL索引原理及慢查询优化
    Markdown 语法整理大集合2017
  • 原文地址:https://www.cnblogs.com/xiongtao/p/10891382.html
Copyright © 2020-2023  润新知