题意:
给你两个数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;
}