POJ 3252 Round Numbers 组合数学

来源:互联网 发布:java开发项目角色 编辑:程序博客网 时间:2024/04/30 11:27

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;}


0 0
原创粉丝点击