Problem Statement
Source: CSES Problem Set — Weird Algorithm
Given a positive integer , apply the following rules repeatedly until becomes :
- If is even, divide it by
- If is odd, multiply it by and add
Print all the values of during the process.
Example: For :
Constraints:
The Math Behind It — Collatz Conjecture
This problem is based on the famous Collatz Conjecture (also known as the problem). The conjecture states that no matter what positive integer you start with, the sequence will always eventually reach .
Despite being incredibly simple to state, this conjecture remains unproven — it’s one of the great unsolved problems in mathematics. Mathematician Paul Erdős once said:
“Mathematics may not be ready for such problems.”
The conjecture has been verified computationally for all integers up to , but no general proof exists.
Approach 1: Direct Simulation (Optimal)
Since the problem just asks us to simulate the process, the straightforward approach is the best one:
- While :
- If is even →
- If is odd →
Time Complexity
There’s no known closed-form for how many steps the sequence takes, but empirically the number of steps is roughly on average. For , the maximum sequence length is around steps (for ), so this is very fast.
Important: Integer Overflow
Even though , intermediate values in the sequence can exceed (the max value of a 32-bit int). For example, starting from , the sequence peaks at — which overflows a 32-bit integer.
Always use long long for this problem.
C++ Solution
#include <iostream>
using namespace std;
int main() {
long long n;
cin >> n;
while (n != 1) {
cout << n << " ";
if (n % 2 == 0)
n /= 2;
else
n = 3 * n + 1;
}
cout << 1 << endl;
return 0;
}
Approach 2: Using Bitwise Operations
We can make the solution slightly more efficient by using bitwise operations:
n & 1checks if is odd (faster thann % 2)n >>= 1divides by 2 (equivalent ton /= 2)
#include <iostream>
using namespace std;
int main() {
long long n;
cin >> n;
while (n != 1) {
cout << n << " ";
if (n & 1)
n = 3 * n + 1;
else
n >>= 1;
}
cout << 1 << endl;
return 0;
}
This doesn’t change the asymptotic complexity but is a micro-optimization that’s common in competitive programming.
Approach 3: Precomputed / Memoized (Overkill Here)
If you had to answer multiple queries (e.g., print sequence lengths for many values of ), you could memoize results. For this particular problem it’s unnecessary since there’s only one query, but it’s worth knowing the technique:
#include <iostream>
#include <unordered_map>
using namespace std;
unordered_map<long long, int> memo;
int collatzLength(long long n) {
if (n == 1) return 0;
if (memo.count(n)) return memo[n];
int steps;
if (n % 2 == 0)
steps = 1 + collatzLength(n / 2);
else
steps = 1 + collatzLength(3 * n + 1);
memo[n] = steps;
return steps;
}
int main() {
long long n;
cin >> n;
// For this problem, just simulate and print
while (n != 1) {
cout << n << " ";
n = (n % 2 == 0) ? n / 2 : 3 * n + 1;
}
cout << 1 << endl;
return 0;
}
Key Takeaways
| Point | Detail |
|---|---|
Use long long | Intermediate values exceed 32-bit range |
| Simple simulation | No fancy algorithm needed — just follow the rules |
| Bitwise tricks | n & 1 and n >>= 1 are minor optimizations |
| Collatz Conjecture | Unproven but assumed to always terminate |
| CSES Difficulty | Introductory — great first problem to start the set |
This is the very first problem in the CSES Problem Set and a perfect warm-up. The real challenge isn’t the code — it’s remembering to use long long! 🚀