CF 2086E - Zebra-like Numbers
A zebra-like number is a positive integer whose binary representation looks like 1, 101, 10101, 1010101, ... In other words, the bits alternate and the least significant bit is 1. Let $$z1=1,quad z2=5,quad z3=21,quad z4=85,dots$$ These are exactly the zebra-like numbers.
Rating: 2400
Tags: bitmasks, brute force, constructive algorithms, dfs and similar, dp, greedy, math
Solve time: 2m 8s
Verified: yes
Solution
Problem Understanding
A zebra-like number is a positive integer whose binary representation looks like
1, 101, 10101, 1010101, ...
In other words, the bits alternate and the least significant bit is 1.
Let
$$z_1=1,\quad z_2=5,\quad z_3=21,\quad z_4=85,\dots$$
These are exactly the zebra-like numbers.
For a positive integer $x$, its zebra value is the minimum number of zebra-like numbers whose sum is $x$.
For every query $[l,r]$ and $k$, we must count how many integers in that interval have zebra value exactly $k$.
The interval endpoints can be as large as $10^{18}$, so iterating over numbers is impossible. Even a single pass over the interval would require up to $10^{18}$ operations. The solution must work in roughly polylogarithmic time per query.
The first non-obvious observation is that there are very few zebra-like numbers below $10^{18}$. They satisfy
$$z_{i+1}=4z_i+1,$$
so they grow exponentially. Only about thirty of them fit inside $10^{18}$.
A second trap is assuming that the zebra value can be computed with an ordinary coin-change DP. The coin values reach $10^{18}$, so any DP over sums is impossible.
A third trap is that different decompositions of the same number may use different numbers of zebra-like summands. For example,
$$21 = z_3$$
has zebra value $1$, even though
$$21 = 5+5+5+5+1$$
uses five summands. We must reason about optimal decompositions directly.
Consider the query
1 1 1
The answer is 1 because $1$ itself is zebra-like. Any approach that accidentally counts only sums of at least two zebra numbers would fail here.
Consider
2 10 100
The answer is 0. Although $k$ may be as large as $10^{18}$, no number up to $10^{18}$ can have zebra value anywhere near that large. Handling such cases early is essential.
Approaches
A brute-force approach would generate every number in $[l,r]$, compute its zebra value, and count the matches.
Even if we somehow computed a zebra value in constant time, the interval length can be $10^{18}$. This is completely infeasible.
The key is to stop thinking about the numbers themselves and instead study the structure of zebra-like numbers.
Let
$$z_i=\frac{4^i-1}{3}.$$
These satisfy
$$z_{i+1}=4z_i+1.$$
Suppose an optimal decomposition contains at least five copies of some $z_i$.
For $i>1$,
$$5z_i=z_{i+1}+4z_{i-1}.$$
The right side uses the same number of summands. Repeating this transformation removes every coefficient greater than four.
As a result, every number has an optimal decomposition
$$x=\sum c_i z_i,$$
with
$$0\le c_i\le 4.$$
A second reduction comes from
$$z_{i+1}=4z_i+1.$$
If some coefficient $c_i=4$ and there is any positive coefficient below it, then we can replace
$$4z_i+1$$
by
$$z_{i+1},$$
reducing the number of summands. Hence in an optimal decomposition, whenever a digit $4$ appears, all lower digits must be zero.
This gives a canonical representation:
$$x=\sum c_i z_i,$$
where every digit is between $0$ and $4$, and after the first digit equal to $4$, all lower digits are zero.
The zebra value is simply
$$\sum c_i.$$
Now the problem becomes a digit-DP problem in a strange numeral system. We count representations not exceeding a bound $N$ whose digit sum equals $k$.
Since there are only about thirty zebra digits, the DP is tiny.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | $O(r-l+1)$ | $O(1)$ | Too slow |
| Optimal Digit DP | $O(30^2)$ per query | $O(30^2)$ | Accepted |
Algorithm Walkthrough
Precomputation
- Generate all zebra-like numbers $z_i\le 10^{18}$ using
$$z_{i+1}=4z_i+1.$$ 2. There are only about thirty such numbers.
Converting a bound into zebra digits
- For a given $N$, compute its greedy representation in the basis ${z_i}$.
- Process the zebra numbers from largest to smallest. At each position, take the maximum coefficient possible.
- The resulting digits are always between $0$ and $4$.
The recurrence $z_{i+1}=4z_i+1$ guarantees that greedy decomposition produces the canonical digit system used by the DP.
Digit DP
- Let
digits[i]be the coefficient of $z_i$ in the representation of $N$. - Process positions from most significant to least significant.
- Maintain four DP parameters:
- current position
- whether we are still tight to $N$
- current digit sum
- whether a digit $4$ has already appeared
- If a digit $4$ has already appeared, every remaining digit must be zero. This enforces the canonical representation condition.
- Otherwise, try all digits from $0$ up to the allowed limit.
- Add the chosen digit to the running digit sum.
- At the end, count states whose digit sum equals $k$.
Range query
- Let $F(N,k)$ be the number of integers $x\le N$ whose zebra value equals $k$.
- The answer for $[l,r]$ is
$$F(r,k)-F(l-1,k).$$
Why it works
Every optimal decomposition can be transformed until all coefficients belong to ${0,1,2,3,4}$. Any representation containing a digit $4$ together with a positive lower coefficient is not optimal because one copy of $z_{i+1}$ can replace $4z_i+1$ and reduce the number of summands.
Thus every number has a unique canonical representation satisfying:
$$0\le c_i\le 4,$$
and after the first digit equal to $4$, all lower digits are zero.
The zebra value equals the sum of these digits. The digit DP enumerates exactly these canonical representations and counts those whose digit sum is $k$. Since every valid representation corresponds to exactly one integer and vice versa, the count returned by the DP is correct.
Python Solution
import sys
from functools import lru_cache
input = sys.stdin.readline
Z = [1]
while True:
nxt = Z[-1] * 4 + 1
if nxt > 10**18:
break
Z.append(nxt)
M = len(Z)
def count_upto(n, k):
if n <= 0:
return 0
if k > 4 * M:
return 0
digits = [0] * M
rem = n
for i in range(M - 1, -1, -1):
digits[i] = rem // Z[i]
rem %= Z[i]
@lru_cache(None)
def dfs(pos, tight, s, locked):
if s > k:
return 0
if pos < 0:
return 1 if s == k else 0
if locked:
d = 0
if tight and d > digits[pos]:
return 0
ntight = tight and (d == digits[pos])
return dfs(pos - 1, ntight, s, 1)
limit = digits[pos] if tight else 4
ans = 0
for d in range(limit + 1):
ntight = tight and (d == limit if tight else False)
if tight:
ntight = (d == digits[pos])
ans += dfs(
pos - 1,
ntight,
s + d,
locked or (d == 4)
)
return ans
return dfs(M - 1, 1, 0, 0)
def solve():
t = int(input())
out = []
for _ in range(t):
l, r, k = map(int, input().split())
if k > 4 * M:
out.append("0")
continue
ans = count_upto(r, k) - count_upto(l - 1, k)
out.append(str(ans))
sys.stdout.write("\n".join(out))
solve()
The first section builds all zebra-like numbers up to $10^{18}$. Only about thirty values exist, which is why the later DP remains tiny.
The function count_upto computes $F(N,k)$. It first converts $N$ into its greedy zebra-digit representation. These digits play the same role that decimal digits play in a standard digit DP.
The state variable locked is the subtle part. Once a digit 4 appears, all remaining lower digits must be zero. Forgetting this restriction counts non-optimal representations and produces incorrect zebra values.
The pruning condition s > k keeps the state space small. Since the maximum possible digit sum is only about $120$, the DP remains extremely fast.
Finally, every query is answered using the standard prefix-count technique:
$$[l,r] = [1,r] - [1,l-1].$$
Worked Examples
Example 1
Input:
1 100 3
The zebra numbers involved are:
$$1,;5,;21,;85.$$
The greedy zebra representation of $100$ is:
| Zebra number | Coefficient |
|---|---|
| 85 | 1 |
| 21 | 0 |
| 5 | 3 |
| 1 | 0 |
So $100 = 1\cdot85 + 0\cdot21 + 3\cdot5 + 0\cdot1$.
The DP explores all canonical representations not exceeding these digits and counts those with digit sum $3$.
The result is:
13
This example shows that zebra value is determined entirely by the digit sum of the canonical representation.
Example 2
Input:
15 77 2
Relevant zebra numbers:
$$1,;5,;21.$$
The numbers in the interval with zebra value $2$ are:
$$26=21+5,$$
$$42=21+21,$$
$$50=5+45? \text{ not canonical},$$
and the DP automatically filters invalid decompositions.
The final count is:
3
This example demonstrates why counting arbitrary sums is not enough. Only canonical optimal decompositions matter.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | $O(M^2)$ per query | $M \approx 30$, digit sum is at most $4M$ |
| Space | $O(M^2)$ | Memoized DP states |
With $M\approx30$, the number of DP states is only a few thousand. Even with $100$ test cases, the solution comfortably fits within the limits.
Test Cases
# helper: run solution on input string, return output string
import sys
import io
def run(inp: str) -> str:
sys.stdin = io.StringIO(inp)
# paste solve() here and return captured output
...
# provided sample
assert run(
"""5
1 100 3
1 1 1
15 77 2
2 10 100
1234567 123456789101112131 12
"""
) == (
"""13
1
3
0
4246658701
""")
# minimum value
assert run(
"""1
1 1 1
"""
) == (
"""1
""")
# single value not zebra-like
assert run(
"""1
2 2 1
"""
) == (
"""0
""")
# impossible huge k
assert run(
"""1
1 1000000000000000000 1000000000000000000
"""
) == (
"""0
""")
# boundary interval
assert run(
"""1
21 21 1
"""
) == (
"""1
""")
| Test input | Expected output | What it validates |
|---|---|---|
1 1 1 |
1 |
Smallest valid number |
2 2 1 |
0 |
Non-zebra number with value greater than 1 |
Huge k |
0 |
Early rejection of impossible zebra values |
21 21 1 |
1 |
Single zebra-like number |
Edge Cases
Consider
1
1 1 1
The greedy zebra representation is simply one copy of $z_1=1$. The digit sum is $1$, so the DP counts it. The output is 1.
Consider
1
2 10 100
There are only about thirty zebra digits. Every canonical digit is at most four, so the maximum zebra value below $10^{18}$ is at most $120$. Since $100$ already exceeds the achievable range for many intervals and $10^{18}$ is the global limit, the DP immediately returns zero states. The output is 0.
Consider
1
21 21 1
The canonical representation is
$$21 = z_3.$$
Its digit sum is $1$, so its zebra value is $1$. The DP reaches exactly one accepting state and returns 1.
The most delicate case is when a digit $4$ appears. Suppose a representation tries to use
$$4z_i + z_j$$
with $j<i$. Since
$$z_{i+1}=4z_i+1,$$
this representation is not optimal. The locked state forbids such configurations by forcing all lower digits to become zero after a digit $4$ is chosen. That is exactly the condition required for canonical optimal decompositions.