Round Numbers--POJ 3252
1、题目类型:组合数学、数论。
2、解题思路:题意,给出两个数a和b,求出[a,b]之间,有多少个数为round number。round number的定义:其二进制数中0的数量大于或等于1。
3、注意事项:右移过程,在匹配1成功时注意怎样取组合数,以及组合数结束的条件。
4、实现方法:
#include<iostream>
#include<cmath>
using namespace std;int i,k,Arr[32];
//计算组合m组中的n组
__int64 C(int m,int n)
{
__int64 r=1;
int h=(m-n)<n?(m-n):n;
for(int i=1;i<=h;i++)
{
r*=m;
r/=i;
m--;
}
return r;
}
void SetTable()
{
Arr[1]=0;
for( i=2;i<=31;i++)
for( k=(i-1)/2+1;k<=i-1;k++)
Arr[i]+=C(i-1,k);
}
int Len(int n)
{
return log(n*1.0)/log(2.0)+1;
}
__int64 Fun(int n)
{
if(n==0)
return 0;
int zero=0,one=1,rightzero,len=Len(n);
__int64 cnt=0;
memset(flag,0,sizeof(flag));
//累加Len(n)之前的和
for(i=1;i<len;i++)
cnt+=Arr[i];
//确定n的那些位为1
for(i=0;i<len;i++)
{
if((n>>i) & 1)
flag[i+1]=true;
else
flag[i+1]=false;
}
for(i=len-1;i>0;i--)
{
//n为偶数
if(len%2==0)
{
rightzero=len/2;
if(flag[i])
{
++one;
for( k=rightzero-zero-1;k<i;k++)
{
if(k>=0)
cnt+=C(i-1,k);
}
}
else
++zero;
}
//n为奇数
else
{
rightzero=(len+1)/2;
if(flag[i])
{
++one;
for( k=rightzero-zero-1;k<i;k++)
{
if(k>=0)
cnt+=C(i-1,k);
}
}
else
++zero;
}
}
zero=0;one=0;
//判断n自身是不是Round Numbers
for(i=1;i<=len;i++)
{
if(flag[i])
one++;
else
zero++;
}
if(zero>=one)
cnt++;
return cnt;
}
int main()
{
int start,finish;
SetTable();
scanf("%d%d",&start,&finish);
ans=Fun(finish)-Fun(start-1);
printf("%I64d\n",ans);
return 0;
}
__int64 ans;
bool flag[32],isOK;