小明有一个由1到n的整数组成的排列,他让你来猜出这个排列是什么。你每次可以猜测某一位置的数字,小明会告诉你所猜测的数是“大了”、“小了”或是“正确”。你想知道你在最坏情况下,需要猜测几次,才能在排列的所有位置都得到小明“正确”的回复?
5
11
用二分法,对于一个长度为 k 的序列,最多搜索
⌊
log
2
k
⌋
+
1
\lfloor \log_2k\rfloor + 1
⌊log2k⌋+1 次,。对于本例,第一个位置有 5 个,那就是 3 次搜索,第二个有 4 个,3 次……
一共 3 + 3 + 2 + 2 + 1 = 11 次。
那我们一个一个计算,然后加上,多简单,复杂度 O ( n ) O(n) O(n)。
然后呢,超时了,寄。
对于每一个 k :
k
=
1
∈
[
2
0
,
2
1
)
k = 1\in[2^0,\ 2^1)
k=1∈[20, 21) == > 搜索
0
+
1
=
1
0 + 1 = 1
0+1=1 次
共
2
0
∗
(
0
+
1
)
=
1
2^0 * (0 + 1) = 1
20∗(0+1)=1 次
k
=
2
∈
[
2
1
,
2
2
)
k = 2\in[2^1,\ 2^2)
k=2∈[21, 22) == > 搜索
1
+
1
=
2
1 + 1 = 2
1+1=2 次
k
=
3
∈
[
2
1
,
2
2
)
k = 3\in[2^1,\ 2^2)
k=3∈[21, 22) == > 搜索
1
+
1
=
2
1 + 1 = 2
1+1=2 次
共
2
1
∗
(
1
+
1
)
=
4
2^1 * (1 + 1) = 4
21∗(1+1)=4次
k
=
4
∈
[
2
2
,
2
3
)
k = 4\in[2^2,\ 2^3)
k=4∈[22, 23) == > 搜索
2
+
1
=
3
2 + 1 = 3
2+1=3 次
k
=
5
∈
[
2
2
,
2
3
)
k = 5\in[2^2,\ 2^3)
k=5∈[22, 23) == > 搜索
2
+
1
=
3
2 + 1 = 3
2+1=3 次
k
=
6
∈
[
2
2
,
2
3
)
k = 6\in[2^2,\ 2^3)
k=6∈[22, 23) == > 搜索
2
+
1
=
3
2 + 1 = 3
2+1=3 次
k
=
7
∈
[
2
2
,
2
3
)
k = 7\in[2^2,\ 2^3)
k=7∈[22, 23) == > 搜索
2
+
1
=
3
2 + 1 = 3
2+1=3 次
共
2
2
∗
(
2
+
1
)
=
12
2^2 * (2 + 1) = 12
22∗(2+1)=12次
k = 8 ……
其实就是个二叉树,求各个节点层数的总和,对于 k ∈ [ 2 i − 1 , 2 i ) k\in [2^{i-1}, \ \ 2^i) k∈[2i−1, 2i) ,有 2 i − 1 2^{i-1} 2i−1个和它一样的(包括它自身)都需要搜索 i i i 次,可以避免多次计算。
图示:

步骤:
i = 0 遍历到 p - 1,每次加上复杂度:
O
(
log
2
n
)
O(\log_2n)
O(log2n)
#include
#include
#include
using namespace std;
int main() {
int n;
cin >> n;
unsigned long long ans = 0;
unsigned long long p = floor(log2(n));
for(int i = 0; i < p; i++) {
ans += (i + 1) * pow(2, i);
}
ans += (p + 1) * (n + 1 - pow(2, p));
cout << ans;
}