Round Numbers (排列组合)
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 7558 | Accepted: 2596 |
Description
The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors, Paper, Stone' (also known as 'Rock, Paper, Scissors', 'Ro, Sham, Bo', and a host of other names) in order to make arbitrary decisions such as who gets to be milked first. They can't even flip a coin because it's so hard to toss using hooves.
They have thus resorted to "round number" matching. The first cow picks an integer less than two billion. The second cow does the same. If the numbers are both "round numbers", the first cow wins,
otherwise the second cow wins.
A positive integer N is said to be a "round number" if the binary representation of N has as many or more zeroes than it has ones. For example, the integer 9, when written in binary form, is 1001. 1001 has two zeroes and two ones; thus, 9 is a round number. The integer 26 is 11010 in binary; since it has two zeroes and three ones, it is not a round number.
Obviously, it takes cows a while to convert numbers to binary, so the winner takes a while to determine. Bessie wants to cheat and thinks she can do that if she knows how many "round numbers" are in a given range.
Help her by writing a program that tells how many round numbers appear in the inclusive range given by the input (1 ≤ Start < Finish ≤ 2,000,000,000).
Input
Output
Sample Input
2 12
Sample Output6
题意:给两个数Start 和 Finish,求介于这两个数之间的二进制表示满足0的个数不大于1的个数的整数个数;
思路:另[0,X]表示0到x之间满足题意的正数的个数,则该题即为求[0,Finish]-[0,Start-1];
[0,X]表示0到x之间满足题意的正数的个数求法:(令num[len]表示长度为len的满足题意的整数个数,c[n][m]表示从n个位置中选出m个位置)(假设x的二进制为1010 0100,其长度是8)
1> 二进制形式长度小于8的肯定小于x,假设长度为len(len < 8)
若len是奇数,len=2*k+1;因第一位都是1,在剩余的2*k位中,0的个数至少是k+1,
则num[len] = c[2k][k+1]+c[2k][k+2]+.....+c[2k][2k];
又因为c[2k][0]+c[2k][1]+c[2k][2]+....+c[2k][2k] = 2^2k,
且c[2k][0]=c[2k][2k],c[2k][1]=c[2k][2k-1]...c[2k][k-1]=c[2k][k+1];推导得num[len]=(2^2k-c[2k][k])/2;
同理,若len是偶数,num[len]=2^(2k-1)/2;
2> 二进制形式长度等于8时,当把除了第一个1之外的1依次变为0得到的数肯定小于x;例如1010 0100变为前缀是100的肯定小于1010 0100,
此时0有两个,在后面的5个数中,0至少有2个,所以共有c[5][2]+c[5][3]+c[5][4]+c[5][5]个;1010 0100还可以变为前缀是1010 00的,
这时0有4个,在后面的两个数中,至少有0个0,共有c[2][0]+c[2][1]+c[2][2]个;还要注意若x本身满足题意,计数器再加1;
1 #include<stdio.h> 2 #include<string.h> 3 const int MS = 31; 4 using namespace std; 5 int power2[MS],c[MS][MS]; 6 int Binary[MS]; 7 8 int RoundNumber(int x) 9 { 10 memset(Binary,0,sizeof(Binary)); 11 if(x <= 1) return 0; 12 int len,i; 13 int number = 0; 14 int num_1,num_0;//记录二进制中1和0的个数; 15 16 num_1 = 0,num_0 = 0; 17 int tmp = x,cnt = 0; 18 19 while(tmp)//将x转化为二进制,其长度为cnt; 20 { 21 int t =tmp%2; 22 Binary[cnt++] = t; 23 tmp = tmp/2; 24 25 if(t == 1) 26 num_1++; 27 else num_0++; 28 29 } 30 31 //求长度小于cnt的roundnumber数; 32 for(len = 1; len <= cnt-1; len++) 33 { 34 if(len%2==1) 35 number += ((power2[len-1]-c[len-1][(len-1)/2])>>1); 36 else number += (power2[len-1]>>1); 37 } 38 39 //求长度等于cnt的roundnumber数; 40 if(num_1 <= num_0) 41 number ++; 42 43 num_1 = 1,num_0 = 0; 44 for(i = cnt-2; i >= 0; i--) 45 { 46 if(Binary[i] == 1) 47 { 48 for(int j = i; j >=0&& j+num_0+1 >= i-j+num_1; j--) 49 number += c[i][j]; 50 num_1++; 51 } 52 else num_0++; 53 } 54 return number; 55 } 56 57 int main() 58 { 59 int n,m; 60 for(int i = 0; i < MS; i++) 61 { 62 c[i][0] = 1; 63 c[i][i] = 1; 64 power2[i] = (1<<i); 65 } 66 67 for(int i = 2; i < MS; i++) 68 { 69 for(int j = 1; j < i; j++) 70 { 71 c[i][j] = c[i-1][j-1] + c[i-1][j]; 72 } 73 } 74 scanf("%d %d",&n,&m); 75 int ans = RoundNumber(m) - RoundNumber(n-1); 76 printf("%d\n",ans); 77 78 return 0; 79 80 }