题意:
给你两个数x,y,让你求这两个数之间的循环数的数量。
循环数:把数转换为二进制,对于二进制,0比1多或者相等的数为循环数。
做法:
先分别求出0~x的循环数个数a,再求出0~y有的循环数个数b;结果为b-a;
求0~x的循环数个数:
假如x转化为2进制之后有5位;x=10100;
则先求出位数为1,2,3,4位的二进制数中有多少个循环数;
求法:比如说位数为4位,则循环数个数为c(3,2)+c(3,3),因为4位第一位肯定为1,后面必须有2或者3个0;
然后再求出二进制为5位,且比10100小的循环数。
求法:可以对10100从第二位到尾进行搜,如果这个位置为0,继续搜,如果为1,就假设此位为0,后面的数中补0或者1使得此二进制为循环数。
比如当第i位为3的时候,此时num[i]=1;若num[i]=0;.则存在c(2,0)+c(2,1)+c(2,2)个循环数。
最后如果y为循环数的话,总体结果加一。
#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
int csum(int x,int y)
{
int sum=1,i;
if(y==0||y==x)return 1;
int chu=1;
for(i=1;i<=y;i++)
{
chu*=i;
sum*=(x-i+1);
if(sum%chu==0)
sum/=chu,chu=1;
}
return sum;
}
int chan(int len,int n0,int n1)
{
if(len==0)return n0>=n1;
int nlen=len;
int i,need0=(nlen+n1-n0+1)/2;
if(need0<0)need0=0;
int sum=0;
for(i=need0;i<=nlen;i++)
{
sum+=csum(nlen,i);
// printf("-------------csum(%d,%d)=%d\n",nlen,i,csum(nlen,i));
}
return sum;
}
int jisuan(long long num,int leap)
{
long long sum;
int sumber;
sum=num;
int lens,i;
int n[100];
lens=0;
while(sum)
{
n[lens++]=sum%2;
sum/=2;
}
sumber=0;
for(i=1;i<lens;i++)
{
sumber+=chan(i-1,0,1);
// printf("first=chan(%d,%d,%d)=%d\n",i-1,0,1,chan(i-1,0,1));
}
if(lens>1)sumber++;
int n1,n0;
n1=1;
n0=0;
// printf("sumber=%d\n",sumber);
for(i=lens-2;i>=0;i--)
{
if(n[i]==0)n0++;
if(n[i]==1)
{
n0++;
sumber+=chan(i,n0,n1);
// printf("chan(%d,%d,%d)=%d\n",i,n0,n1,chan(i,n0,n1));
n1++;n0--;
}
}
if(lens==1)
sumber++;
if(leap==1&&n0>=n1)sumber++;
return sumber;
}
int main()
{
long long st,end;
cin>>st;
cin>>end;
int x;
int y;
x=jisuan(st,0);
y=0;
y=jisuan(end,1);
printf("%d\n",y-x);
return 0;
}