D - ロープの分割 / Splitting a Rope Editorial by admin
GPT 5.2 HighOverview
This is a problem where we have a rope divided into segments of given lengths, and we cut it at segment boundaries to divide it into \(K\) pieces, minimizing the “length of the longest rope.” We binary search on the answer (the minimum of the maximum length) and greedily check whether a division is possible for a given upper limit.
Analysis
Key Insight
Consider the decision problem: “Can we make all rope pieces have length at most \(x\)?”
- If we can divide with upper limit \(x\), then we can always divide with any larger upper limit \(x' \ge x\) (the condition becomes more relaxed).
- Conversely, if it’s impossible with \(x\), it’s obviously impossible with any smaller upper limit.
In other words, the decision result has monotonicity with respect to \(x\) (it switches from false to true exactly once). Because of this property, we can use binary search to find the minimum \(x\) that gives “true.”
Why a Naive Approach Is Difficult
If we try all possible ways to cut (choosing \(K-1\) cut positions), there are \(\binom{N-1}{K-1}\) combinations, which is far too many for \(N \le 10^5\).
How to Build the Decision Function (Greedy)
Given an upper limit \(x\), we process segments from left to right:
- If adding the next segment to the current rope keeps it at most \(x\), add it.
- If it would exceed \(x\), cut here and start a new rope.
This is optimal (= minimizes the number of ropes needed). If the number of ropes produced by this greedy approach is at most \(K\), then “\(x\) is feasible” (since we can leave extra cuts unused, it’s possible to adjust to exactly \(K\) pieces).
Concrete Example
Let \(A=[2,3,4,2],\ K=2\), and check the upper limit \(x=6\):
- 2 + 3 = 5 (still OK)
- Adding the next 4 gives 9, which exceeds → cut (1st rope is 5)
- 2nd rope is 4 + 2 = 6
It fits in 2 ropes, so it’s feasible (true). On the other hand, with \(x=5\): 2+3=5, then cut, next is 4, adding 2 gives 6 which exceeds, so cut again — total of 3 ropes, which is infeasible (false).
Algorithm
- Determine the search range
- Lower bound \(lo = \max(A)\) (no matter how we cut, each segment must belong to some rope, so we can’t make the maximum shorter than the longest single segment)
- Upper bound \(hi = \sum A\) (if we don’t cut at all, we have 1 rope of this length)
- Build the decision function
can(x)- Greedily pack from left, counting the number of ropes
cnt - If
cnt > K, return infeasible (false) - If we reach the end, return feasible (true)
- Greedily pack from left, counting the number of ropes
- Use the monotonicity of
can(x)to binary search over \([lo, hi]\)- If
can(mid)is true, sethi = mid - If false, set
lo = mid + 1
- If
- The value of
lowhen the search ends is the answer
Complexity
- Time complexity: \(O(N \log(\sum A))\) (The decision function is \(O(N)\), and binary search runs \(\log(\sum A)\) times)
- Space complexity: \(O(1)\) (excluding the input array)
Implementation Notes
Initialize the binary search with
lo = max(A),hi = sum(A)(this ensures the range narrows correctly).In the greedy decision, strictly follow the rule “cut when it exceeds,” and return early when
cnt > Kfor efficiency.An important point is that it suffices to make at most \(K\) pieces (since not making extra cuts won’t increase the count, if
cnt <= Kwe can adjust to exactly \(K\) pieces).Source Code
import sys
def main():
input = sys.stdin.readline
N, K = map(int, input().split())
A = list(map(int, input().split()))
lo = max(A)
hi = sum(A)
def can(x: int) -> bool:
cnt = 1
s = 0
for a in A:
if s + a <= x:
s += a
else:
cnt += 1
s = a
if cnt > K:
return False
return True
while lo < hi:
mid = (lo + hi) // 2
if can(mid):
hi = mid
else:
lo = mid + 1
print(lo)
if __name__ == "__main__":
main()
This editorial was generated by gpt-5.2-high.
posted:
last update: