C - 丸太の分割 / Splitting Logs 解説 by admin 印刷ページ
Claude 4.6 Opus (Thinking)Overview
Given a log consisting of \(N\) parts, we want to cut it at \(K\) locations to divide it into \(K+1\) fragments, minimizing the maximum length among the fragments. This can be solved using the classic technique of binary search on the answer.
Analysis
Key Insight: “Fix the answer”
This problem has the form “minimize the maximum value.” For this type of problem, the approach of fixing the answer value \(M\) first and then determining whether it is achievable is extremely effective.
Specifically, we consider the following decision problem:
“Can we divide the log using at most \(K\) cuts so that each fragment has length at most \(M\)?”
If we can answer this decision problem, we can efficiently find the value of \(M\) using binary search.
Why a naive approach doesn’t work
There are \(\binom{N-1}{K}\) ways to choose the cut positions, and when \(N\) is large, exhaustive search is far too slow.
Greedy solution for the decision problem
Determining whether we can divide the log with a maximum length of \(M\) or less can be done greedily in \(O(N)\). We add parts from left to right, and whenever the running total exceeds \(M\), we make a cut there and start a new fragment. If the number of cuts needed is at most \(K\), we judge it as “achievable.”
Concrete example
When \(A = [3, 5, 4, 7, 3]\), \(K = 2\):
- Try \(M = 10\) → \([3,5]\) (sum 8), \([4]\) then adding 7 gives 11 > 10 so cut → \([4,\,]\) cut and \([7,3]\) (sum 10) → 2 cuts → OK
- Try \(M = 9\) → \([3,5]\) (8), adding 7 to \([4]\) gives 11 > 9 → cut, adding 3 to \([7]\) gives 10 > 9 → cut → 3 cuts → NG
Therefore the answer is \(10\).
Algorithm
Determine the binary search range
- Lower bound \(lo = \max(A)\) (no matter how we divide, a single part cannot be split)
- Upper bound \(hi = \sum A\) (the length when no cuts are made at all)
Binary search
- For \(mid = \lfloor (lo + hi) / 2 \rfloor\), call the decision function
can_split(mid) - If achievable, set \(hi = mid\) (an even smaller value might be possible)
- If not achievable, set \(lo = mid + 1\) (a larger value is needed)
- When \(lo = hi\), that is the answer
- For \(mid = \lfloor (lo + hi) / 2 \rfloor\), call the decision function
Decision function
can_split(max_len)- Add parts from left to right; when the running total exceeds
max_len, increment the cut count by 1 and reset the total - If a single part exceeds
max_len, immediately returnFalse - If the final cut count is at most \(K\), return
True
- Add parts from left to right; when the running total exceeds
Complexity
- Time complexity: \(O(N \log S)\) (where \(S = \sum A_i\))
- The binary search loop runs \(O(\log S)\) times, and each decision check takes \(O(N)\)
- Space complexity: \(O(N)\) (for storing the array \(A\))
Implementation Notes
By setting the lower bound of the binary search to \(\max(A)\), the case where “a single part exceeds
max_len” will not occur after the initial check within the decision function, but a guard condition is included for safety.In the greedy approach, when “the total exceeds
max_len, make a cut,” the new fragment after the cut starts from the part that caused the excess (current = a).Fast input using
sys.stdin.read()is employed to avoid TLE even with large inputs.Source Code
import sys
def solve():
input_data = sys.stdin.read().split()
N = int(input_data[0])
K = int(input_data[1])
A = [int(input_data[i + 2]) for i in range(N)]
def can_split(max_len):
cuts = 0
current = 0
for a in A:
if a > max_len:
return False
current += a
if current > max_len:
cuts += 1
current = a
return cuts <= K
lo = max(A)
hi = sum(A)
while lo < hi:
mid = (lo + hi) // 2
if can_split(mid):
hi = mid
else:
lo = mid + 1
print(lo)
solve()
This editorial was generated by claude4.6opus-thinking.
投稿日時:
最終更新: