POJ3252 组合数学

POJ3252

问题重述:

求解在区间[start, finish]之间的Round Number的数目。所谓Round Number指的是,二进制表示中0的位数大于等于1的位数的整数。

分析:

1.假如能够分别得到[0, finish] 和 [0, start - 1]区间内的Round Number的数目n1, n2, 那么问题的答案就是n1 - n2. 因此问题可以转化为求解小于n的Round Number的数目。

2.假设整数N的二进制表示为 1,n2,n3,n4,..nk, 则可以把小于N的roundnumber的数目分为两个部分

  1)二进制表示位数小于k的Round Number的个数。

   容易知道位数为j的Round Number的个数为 C[j-1][0] + C[j - 1][1] + ... + C[j - 1][j / 2 - 1]。

  2)位数为k且小于N的Round Number的个数。

  M小于N可以理解为:M和N的二进制表示在出现第一个不同位之前的所有位都相同,且mj = 0, nj = 1,(j表示第一个不同位的序号)。因此小于N的Round Number的数目可以通过如下算法计算:找到N中非零位nj = 1, 令mj=0, 且m1 = n1, m2 = n2,.., mj-1   = nj-1,这样只需要令剩余的k - j位的非零位的数目使M满足Round Number的条件即可。

  例如对于N=1010010, 1)令M = 100xxxx, 那么M的后4位最多只能有2个1,因此满足该形式的M的个数有C[4][0] + C[4][1] + C[4][2]; 2)令M = 101000X, 则满足条件的M的个数为C[1][0] + C[1][1].

根据以上分析即可求解此问题。

AC代码

 1 //Memory: 232K        Time: 16MS

 2 #include <iostream>

 3 #include <cstring>

 4 #include <cstdio>

 5 

 6 using namespace std;

 7 

 8 int c[64][64];

 9 int n[64];

10 

11 void init_c()

12 {

13     for (int i = 0; i < 64; i++) {

14         c[i][0] = 1;

15         c[i][i] = 1;

16     }

17     for (int i = 2; i < 64; i++)

18         for (int j = 1; j < i; j++)

19             c[i][j] = c[i - 1][j] + c[i - 1][j - 1];

20 }

21 

22 int a[40];

23 int len = 0;

24 

25 int roundNum (long long n)

26 {

27     len = 0;

28     while(n) {

29         a[len++] = n % 2;

30         n /= 2;

31     }

32     int ret = 0;

33     

34     for (int i = 2; i < len; i++) {

35         for (int j = 0; j <= i / 2 - 1; j++) {

36             ret += c[i - 1][j];

37         }

38     }

39 

40     int cnt = 1;

41     for (int i = len - 2; i >= 0; i--) {

42         if (cnt > len / 2) break;

43         if ( a[i] ) {

44             for (int j = 0; j <= len / 2 - cnt; j++)

45                 ret += c[i][j];

46             cnt++;

47         }

48     }

49 

50     return ret;

51 }

52 

53 int main()

54 {

55     init_c();

56     long long s, f;

57     cin >> s >> f;

58     cout << roundNum(f + 1) - roundNum(s) << endl;

59     return 0;

60 }

 

你可能感兴趣的:(poj)