Topics
Caracal is fighting with a monster. The health of the monster is H.
Caracal can attack by choosing one monster. When a monster is attacked, depending on that monster’s health, the following happens:
- If the monster’s health is 1, it drops to 0
- If the monster’s health, X, is greater than 1, that monster disappears. Then, two new monsters appear, each with the health of
X/2
(floor)
Caracal wins when the healths of all existing monsters become 0 or below. Find the minimum number of attacks Caracal needs to make before winning.
Idea
Approach 1: Recursion
When you attack a monster with health (where ), you effectively replace it with two monsters that must be cleared later. This gives a recurrence:
with the base case (a monster with health 1 is cleared in one attack).
Approach 2: Binary Tree representation
Think of each attack as a node in a binary tree:
- An attack on a monster with health creates two “child” attacks (one for each new monster)
- If a monster has health 1, it becomes a leaf in the tree since one attack finishes it
The height of this binary tree will be (we keep dividing by 2 until we get 1). Example: , root will be , then children will be and their children will be . Thus height of this binary tree is 3. Consequently, num of nodes in binary tree: .
Observe that is also the number of bits required to represent in binary. This can be efficiently calculated using: (64 - __builtin_clzll(n))
(if is a long dtype).
Code
// Approach 1 O(log n)
ll attacks(ll health) {
if (health <= 1)
return 1;
ll x = attacks(health / 2);
return 1 + x + x;
}
void solve() {
ll n;
cin >> n;
cout << attacks(n) << endl;
}
// Approach 2 O(1)
void solve() {
ll n;
cin >> n;
if(n==1){
cout << 1;
return 0;
}
ll b = 1LL << (64- __builtin_clzll(n)); // 2^h
cout << b-1 << endl;
}