D - Divide Interval Editorial by evima

Another Solution

I will describe a policy that recurses top-down. (It is almost the same as the recursive implementation of a segment tree.) Hereafter, let \([l, r)\) denote the sequence \(l, l+1, \dots, r-2, r-1\).

For a good sequence \([l, r)\), let \(f(l, r, L, R)\) denote the optimal partition of the intersection between it and the input sequence \([L, R)\). (We ignore the case without intersection.) The answer is \(f(0, 2^{60}, L, R)\).

Let’s determine \(f(l, r, L, R)\) recursively.

  • If the entirety of \([l, r)\) is contained in \([L, R)\), the intersection is \([l, r)\), and this itself is the optimal “partition.”
  • Otherwise, let \(m = (l + r) / 2\). Here, both the left half \([l, m)\) and the right half \([m, r)\) of \([l, r)\) are good sequences.
    • If the entirety of \([L, R)\) is contained in the left half \([l, m)\), that is, if \(R \leq m\), the right half can be ignored, and the optimal partition is \(f(l, m, L, R)\).
    • If the entirety of \([L, R)\) is contained in the right half \([m, r)\), that is, if \(m \leq L\), the left half can be ignored, and the optimal partition is \(f(m, r, L, R)\).
    • If neither of the above conditions is met, then \([L, R)\) intersects with both the left and right halves of \([l, r)\), and the optimal partition is the concatenation of \(f(l, m, L, R)\) and \(f(m, r, L, R)\).

Implementing this as a recursive function and calling \(f(0, 2^{60}, L, R)\) will result in the number of recursive calls being four or less per layer (see the diagram in the official editorial), with a total of \(60 \times 4\) calls or less.

Sample Implementation (Python):

def f(l, r, L, R):
    if L <= l and r <= R:
        return [(l, r)]
    m = (l + r) // 2
    if R <= m:
        return f(l, m, L, R)
    if m <= L:
        return f(m, r, L, R)
    return f(l, m, L, R) + f(m, r, L, R)


L, R = map(int, input().split())
ans = f(0, 1 << 60, L, R)
print(len(ans))
for l, r in ans:
    print(l, r)

posted:
last update: