题解:使用排列组合的知识解决!!!
主要求1-n之间的Round Numbers,然后减下就可以了,现在主要就是怎样求n以内的Round Numbers数。
分2部分求:
1.计算出n的2进制位数为m,这1-(m-1)之间的数可以很快求出,
当为偶数2k的时候:C(2k-1,k)+C(2k-1,k+1)+……+C(2k-1,2k-1)=2^(2k-2);
当为奇数2k+1的时候:C(2k,k+1)+C(2k,k+2)+……+C(2k,2k)=2^(2k-1)-1/2*C(2k,k);
2.再就是求m个2进制位时的Round Numbers数。由于第一个数一定是1所以不变然后继续向低位扫描,并计数0的个数,
当扫描到i位时是1,算出后面至少需要k个0,则不大于n且是Round Numbers的个数为C(i,k)+C(i,k+1)+……+C(i,i);
直到扫描结束。最后还需判断n本身满足不!!!
代码如下:
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<iomanip> 5 #include<cmath> 6 #include<cstring> 7 #include<vector> 8 #define ll __int64 9 #define pi acos(-1.0) 10 #define MAX 50000 11 using namespace std; 12 int c[100],a[33],num1,num0,cm[32][32]; 13 int pows(int b) 14 { 15 return 1<<b; 16 } 17 int C(int n){ 18 int ans=pows(n-2); 19 if (n&1) 20 ans -= cm[n-1][(n-1)/2]/2; 21 return ans; 22 } 23 void init(){ 24 int i,j; 25 for (i=0;i<31;i++) cm[i][0]=1,cm[i][i]=1; 26 for (i=2;i<31;i++) 27 for (j=1;j<i;j++) 28 cm[i][j] = cm[i-1][j]+cm[i-1][j-1]; 29 c[0]=c[1] = 1; 30 for (i=2;i<31;i++){ 31 c[i] = C(i)+c[i-1] ; 32 } 33 } 34 int binum(int n){ 35 int num=0; 36 num1=0; 37 while (n){ 38 a[num++] = n%2; 39 num1 += n%2; 40 n/=2; 41 } 42 return num; 43 } 44 int fun(int n){ 45 int ans = 0,i0=0,j,k; 46 int num = binum(n); 47 num0 = num - num1; 48 ans = c[num-1]; 49 j=(num+1)/2; 50 if (num0>=num1) ans++; 51 if (num!=1) 52 for (int i=num-2;i>=0;i--){ 53 if (a[i]){ 54 if(i0+1>=j) ans += pows(i); 55 else 56 for (k=j-i0-1;k<=i;k++){ 57 ans += cm[i][k]; 58 } 59 } 60 else i0++; 61 } 62 return ans; 63 } 64 int main(){ 65 init(); 66 int n,m; 67 scanf("%d%d",&n,&m); 68 printf("%d ",fun(m)-fun(n-1)); 69 return 0; 70 }