POJ 3252 Round Numbers 组合数学

http://poj.org/problem?id=3252

题意


输入两个十进制正整数a和b,求闭区间 [a ,b] 内有多少个Round number

所谓的Round Number就是把一个十进制数转换为一个无符号二进制数,若该二进制数中0的个数大于等于1的个数,则它就是一个Round Number

注意,转换所得的二进制数,最高位必然是1,最高位的前面不允许有0

思路
1 首先计算长度小于len的RN数有多少
  (由于这些数长度小于len,那么他们的值一定小于k,因此在进行组合时就无需考虑组合所得的数与k之间的大小了)
2 后计算长度等于len的RN数有多少(由于这些数长度等于len,那么他们的值可能小于k,可能大于k,因此在进行组合时就要考虑组合所得的数与k之间的大小了)

int zero=0;  //从高位向低位搜索过程中出现0的位的个数

从高位到低位搜索过程中,遇到当前位为0,则不处理,但要用计数器zero累计当前0出现的次数

遇到当前位为1,则先把它看做为0,zero+1, 那么此时当前位 后面的 所有低位任意组合都会比k小,找出这些组合中RN的个数,统计完毕后把当前位恢复为原来的1,然后zero-1,

继续向低位搜索



注意:Round(y+1);

///Count(y+1)的得到小于  y+1 的 RN 数的个数 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<cstdlib>
using namespace std;
int a[35][35];
void solve()///初始化
{
    memset(a,0,sizeof(a));
    for(int i=0; i<32; i++)///注意a[0][0]=1 ;
    {
        for(int j=0; j<=i; j++)
        {
            if(i==j||j==0)
                a[i][j]=1;
            else
                a[i][j]=a[i-1][j]+a[i-1][j-1];
        }
    }
}
char s[1000];
int Count(int x)
{
    int sum=0;
    int top=0;
    while(x)
    {
        s[++top]=x%2;   ///变成二进制
        x/=2;
    }
    for(int i=1; i<top-1; i++)         ///位数小于长度的个数
        for(int j=0; j<=(i-1)/2; j++)         ///使用1的个数   他的组合数与排列0的种类数的组合数相同
            sum+=a[i][j];
    int zero=0;
    for(int i=top-1; i>0; i--)
    {
        if(s[i])
        {
            ///  x最少需要(top1+1)/2个0
            ///  zero表示前面已经用了0的个数
            /// +1 表示该位置正在使用一个0
            for(int j=(top+1)/2-(zero+1); j<=i-1; j++)
                sum+=a[i-1][j];
        }
        else                  ///统计已经使用了多少个0
            zero++;
    }
    return sum;
}
int main()
{
    int x,y;
    solve();
    while(~scanf("%d%d",&x,&y))
    {
       // printf("%d\n%d\n",Count(x),Count(y));
       ///Count(y+1)的得到小于  y+1 的 RN 数的个数 
        printf("%d\n",Count(y+1)-Count(x));
    }
    return 0;
}


你可能感兴趣的:(POJ 3252 Round Numbers 组合数学)