Gym611B-New Year and Old Property-简单模拟

【题目大意】给出两个数a,b.求出在[a,b]区间中二进制形式只包含一个0的数字个数。

【解题思路】对于满足整数域中满足上面要求的数字都是可以按序求出的,例如10,101,110,1011,1101,1110…并且当二进制的长度(不为零的最高位)确定,该长度的满足要求数字个数是确定的。并且可以根据规律求出。

因此,可以求得≥a且最小的 满足要求的数A(用(l1,z1)表示。L:二进制长度,Z:唯一一个0的位置)同理也有≤b的最大的数B(l2,z2),进而可以根据A和B得出ans。

代码如下

 1 #include "iostream"
 2 using namespace std;
 3 int Slong(long long s) //求出数字长度
 4 {
 5     int i = 0;
 6     while (s)
 7     {
 8         s = s / 2;
 9         i++;
10     }
11     return i;
12 }
13 long long getnz(int n, int z)//根据数字长度(二进制)和0的位置==>十进制数字
14 {
15     long long i = 1;
16     long long k = 0;
17     for (int j = 1 ; j <= n ; j++)
18     {
19         if ( j != z )  k += i;
20         i *= 2;
21     }
22     return k;
23 }
24 int main()
25 {
26     long long a, b;
27     int n1 = 0, n2 = 0, z1 = 0, z2 = 0;
28     cin >> a >> b;
29     int l = Slong(a);
30     if (a > getnz(l, 1))
31         // 边界:如果a比该长度下最大的满足要求数字还大,
32         // A的为(L+1,L)
33         // 长度比a长1第二高位为0
34         // (例:10111111111111111……)
35     {
36         n1 = l + 1;
37         z1 = l;
38     }
39     else
40         for ( int i = l - 1 ; i >= 1 ; i-- ) //从小到大枚举该长度下的数字,求A
41         {
42             if (getnz(l, i) >= a)
43             {
44                 n1 = l;
45                 z1 = i;
46                 break;
47             }
48         }
49     l = Slong(b);
50     if (b < getnz(l, l - 1))
51         // 边界:如果b比该长度下最小的满足要求数字还小,
52         // A的为(L-1,1)
53         // 长度比a小1第一位为0
54         // (例:11111……1110 )
55     {
56         n2 = l - 1;
57         z2 = 1;
58     }
59     else
60         for ( int i = 1 ; i < l ; i++ )// 从大到小枚举该长度下数,求得B
61         {
62             if (getnz(l, i) <= b)
63             {
64                 n2 = l;
65                 z2 = i;
66                 break;
67             }
68         }
69     //n1,n2表示A,B长度     z1,z2 表示A,B中0的位置
70     int ans;
71     if (n1 > n2) ans = 0;  //ans = 0的情况
72     else if (n1 == n2)  ans = (z1 - z2) + 1;
73     else ans = (n1 + n2 - 2) * (n2 - n1 - 1) / 2 + z1 + n2 - z2;
74     //  求得长度[n1+1,n2-1]中数字个数【 (n1 + n2 - 2) * (n2 - n1 - 1) / 2】
75     // 长度n1中数字个数   【z1】
76     // 长度n2中数字个数   【n2 - z2】
77     cout << ans << endl;
78 }

 

posted @ 2016-10-15 17:14  HITLJR  阅读(291)  评论(0编辑  收藏  举报