POJ3252-Round Numbers 数学
题目链接:http://poj.org/problem?id=3252
题目大意:
输入两个十进制正整数a和b,求闭区间 [a ,b] 内有多少个Round number
所谓的Round Number就是把一个十进制数转换为一个无符号二进制数,若该二进制数中0的个数大于等于1的个数,则它就是一个Round Number
规定输入范围: 1<= a <b<=2E
/*
一开始错在计算组合数!!!正解是利用杨辉三角来算!!
另外对于star=1的情况下也需要特判一下子
思路是算出【0,star】和【0,fini】的round number(以下简称rn)个数,后者减去前者+1*【star是rn】(艾弗森约定)
要计算【0,a】的rn个数,设a的二进制表示长度为lena,那么先打表f[]给出二进制表示数长度为1-->lena-1的这些数的rn。
再计算长度为lena的,但是比a小的这些数里头有哪些是rn呢?
计算同长度的rn的思路是:从高位到低位将a的二进制表示中的1(除最高位)逐次变为0,更低位的则在满足rn条件的前提下随便进行排列,得到的数一定是小于a的rn
当然某一位变完了以后又会变回来的啊。这部分详见fun();
*/
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 using namespace std; 6 #define MAX 35 7 #define unsigned int long long 8 long long f[MAX]; 9 long long star,fini; 10 char str0[35],str1[35]; 11 long long c[40][40]; 12 void d2b(long long d, char *str)//十进制转成二进制! 13 { 14 int nStart = -1, i = 0; 15 for (i=0; i<32; i++) 16 { 17 bool bOne = (0 != (d & (1 << (32-i-1) ))); 18 if (bOne && nStart < 0) 19 { 20 nStart = i; 21 } 22 if(nStart>=0) 23 { 24 str[i - nStart] = bOne ? '1' : '0'; 25 } 26 } 27 str[i - nStart] = '\0'; 28 return ; 29 } 30 31 long long pow3( long long a, long long b )//快速幂 32 { 33 long long r = 1, base = a; 34 while( b != 0 ) 35 { 36 if( b & 1 ) 37 r *= base; 38 base *= base; 39 b >>= 1; 40 } 41 return r; 42 } 43 44 void play_table(void)//计算组合数的! 45 { 46 for(int i=0;i<=35;i++) 47 for(int j=0;j<=i;j++) 48 if(!j || i==j) 49 c[i][j]=1; 50 else 51 c[i][j]=c[i-1][j-1]+c[i-1][j]; 52 return; 53 } 54 55 void Cf()//计算f[] 56 { 57 f[1]=1; 58 for(int i=2;i<MAX;i++){ 59 int k=i/2; 60 if(i%2) 61 f[i]=(pow3(2,2*k)-c[2*k][k])/2; 62 else 63 f[i]=pow3(4,k-1); 64 } 65 } 66 67 long long fun(char ss[35]) 68 { 69 int sum0=0;//ss中0的个数。 70 int len=strlen(ss); 71 long long ans=0; 72 for(int i=1;i<len;i++) 73 ans+=f[i]; 74 for(int k=1;k<len;k++) 75 { 76 if(ss[k]=='0') 77 sum0++; 78 else 79 { 80 int t0=ceil(1.0*len/2)-sum0-1;//至少需要的0个数 81 int s=len-k-1;//剩下的可变位数 82 if(t0<=0) 83 ans+=pow3(2,s); 84 else 85 if(t0<=s) 86 for(int i=t0;i<=s;i++) 87 ans+=c[s][i];//(s,i); 88 } 89 } 90 if(sum0>=ceil(1.0*len/2))//相当于本身 91 ans++; 92 return ans; 93 } 94 95 bool ok(char s[35]) 96 { 97 int sum0=0; 98 int len=strlen(s); 99 if(strcmp(s,"1")==0) 100 return 0; 101 for(int i=1;i<len;i++) 102 if(s[i]=='0') 103 sum0++; 104 if(sum0>=ceil(1.0*len/2)) 105 return 1; 106 return 0; 107 } 108 109 int main() 110 { 111 play_table(); 112 Cf(); 113 while(cin>>star>>fini) 114 { 115 d2b(star,str0); 116 d2b(fini,str1); 117 if(star==1) ans0++;//对1进行特判 118 if(ok(str0)) 119 cout<<fun(str1)-fun(str0)+1<<endl; 120 else 121 cout<<fun(str1)-fun(str0)<<endl; 122 } 123 return 0; 124 }