首页 > 代码库 > poj 3252 Round Numbers (组合数学)

poj 3252 Round Numbers (组合数学)

链接 :poj 3252

题意:一个数转化成二进制之后,0的个数大于等于1的为round数,

给定一个区间[m,n],问这区间内有多少round数

分析:要求[m,n]间的的round数,

可以用[1,n+1)的个数减去[1,m)的个数,

对于比N小的round数的个数:

化为二进制的长度比N的长度小的数:如果长度为L,那么高位肯定是1,

然后枚举0的个数,利用组合数求即可

长度和N相等但比N小的数:

从高位开始枚举,若出现1,则将这位看作0,再枚举之后的低位,肯定是比原数小的

依次下去,注意统计好高位已经出现的0,1个数。


#include<stdio.h>
#define max(a,b) a>b?a:b
int len,c[35][35];
char s[35];
void com()   //求组合数(杨辉三角)
{
    int i,j;
    for(i=0;i<=32;i++){
        c[i][0]=c[i][i]=1;
        for(j=1;j<i;j++)
            c[i][j]=c[i-1][j-1]+c[i-1][j];
    }
}
void bin_num(int x)
{
    int zero,one;
    len=zero=one=0;
    while(x){
        if(x%2)
            one++;
        else
            zero++;
        s[len++]=x%2+'0';
        x/=2;
    }
}
int round(int x) //[1,x)区间内round的个数
{
    int i,j,cnt=0,zero=0;
    bin_num(x);           //将x化为二进制
    for(i=1;i<len-1;i++)      //求二进制长度比x小的round数个数
        for(j=i/2+1;j<=i;j++)
            cnt+=c[i][j];
    for(i=len-2;i>=0;i--){   //求长度与x相等,比x小的round数个数
        if(s[i]=='1'){     //若某一位为1,将其变为0,再枚举0的个数
            zero++;
            for(j=max(0,(len+1)/2-zero);j<=i;j++)
                cnt+=c[i][j];
            zero--;      //再将该位恢复,继续上述操作
        }
        else
            zero++; //统计0的个数
    }
    return cnt;
}
int main()
{
    int m,n;
    while(scanf("%d%d",&m,&n)!=EOF){
        com();
        printf("%d\n",round(n+1)-round(m));
    }
    return 0;
}


poj 3252 Round Numbers (组合数学)