Introduction
This article reviews my solution to P1121 Maximum Sum of Two Circular Subarrays on Luogu. The central algorithmic idea—combining case analysis with a complementary formulation—was correct in my first implementation. However, a boundary case caused by the nonempty constraint prevented that version from passing every test. I will examine exactly how that case arises, then show how a one-line fix takes the implementation from 80 points to the final 100-point solution.
Problem Analysis
The essential parts of the problem are:
- Layout: The elements form a circle.
a[1]anda[n]are adjacent, so a contiguous subarray can wrap from the end of the array back to the beginning. - Objective: Choose two nonoverlapping, nonempty contiguous subarrays with the largest possible total sum. The nonempty constraint is crucial when handling boundary cases.
- Constraints:
Ncan be as large as2e5, so the algorithm must run inO(N)orO(N log N)time.
We need to maximize the sum of two subarrays on a circle. The challenge is to design a linear-time algorithm that handles both the circular structure and the requirement to choose two subarrays.
Algorithm Design and Implementation
V1.0: Initial Implementation (80 Points)
Design
Direct dynamic programming on a circle makes states difficult to define because there is no fixed starting or ending point. I therefore used the standard approach of breaking the circular problem into linear problems.
Every possible choice of two subarrays falls into one of two cases, depending on whether the selection crosses the connection between a[1] and a[n]:
- Case 1: Neither chosen subarray crosses the
a[1]–a[n]connection.- Reduction: This is equivalent to finding the maximum sum of two subarrays on the line
a[1...n]. - Solution: Enumerate a dividing point. There must be a dividing point between the two optimal subarrays
S1andS2on the line.
a. Use dynamic programming to precompute two auxiliary arrays:max_L_to_R[i]: the maximum sum of a single subarray anywhere within the prefixa[1...i].max_R_to_L[i]: the maximum sum of a single subarray anywhere within the suffixa[i...n].
b. Iterate over every possible dividing pointi, from1ton-1, and calculatemax_L_to_R[i] + max_R_to_L[i+1].
c. The largest of these sums is the answer for Case 1.
- Reduction: This is equivalent to finding the maximum sum of two subarrays on the line
Figure legend: The red outline is the circular array, with the cut between a[n] and a[1]. Purple arcs mark the selected subarrays. The handwritten label means “does not cross the cut.”
- Case 2: The chosen subarrays cross the
a[1]–a[n]connection.- Reduction: In this case, one subarray lies at the end of the array and the other at the beginning. To simplify the calculation, consider the complement.
- Reasoning:
(选中元素的和) = (数组总和) - (未选中元素的和). In English: the sum of selected elements equals the total array sum minus the sum of unselected elements. - Key observation: If the selected portion wraps around, the unselected portion must not wrap around.
- Further reduction: Maximizing the sum of selected elements is equivalent to minimizing the sum of unselected elements.
- Solution:
a. Reduce the problem to finding the minimum sum of two subarrays on the linea[1...n].
b. Use the symmetric version of the method from Case 1: computemin_L_to_Randmin_R_to_L, then find the minimum sum of two subarrays on the line.
c. Subtract this value from数组总和, the total array sum, to obtain the answer for Case 2.
Figure legend: The purple selection crosses the cut between a[n] and a[1]. The handwritten label means “crosses the cut.” The unselected portions remain ordinary subarrays on the line.
The final answer is max(情况一的解, 情况二的解): the larger of the answers for Case 1 and Case 2. The algorithm runs in O(N) time.
Implementation
Expand/collapse the V1.0 80-point code
1 |
|
What Went Wrong
Root cause:
The theoretical model is correct, but the implementation misses a special case introduced by the nonempty constraint. It fails on tests where the input array contains only negative numbers.Why it fails:
- When every element is negative, minimizing the sum means choosing as many elements as possible. The computed minimum sum of two subarrays on the line therefore equals the total array sum.
- The calculation
total_a - min_valincase_2()then becomestotal_a - total_a, producing0. - Under the nonempty constraint, the sum of any two nonempty subarrays in an all-negative array must be negative.
case_1()correctly computes the optimal negative result. - Finally,
maincomparesmax(一个正确的负数, 0)—the larger of the correct negative value and zero—and incorrectly chooses0. - This result of
0corresponds to leaving every element unselected, or selecting the empty set, which violates the problem’s nonempty constraint.
V2.0: Corrected Implementation (AC)
Design
The problem is now clear: when the minimum sum of two subarrays on the line == total array sum, case_2() produces an invalid answer of 0.
The fix must recognize this situation and ensure that the invalid result cannot become the final answer.
- Solution: Change the return value of
case_2(). Whentotal_a == min_val, return the smallest possible sentinel value,LLONG_MIN, rather than0. - Effect: Every valid solution, including a negative one, must be greater than
LLONG_MIN. In the finalmaxcomparison, the valid answer fromcase_1()therefore automatically replaces theLLONG_MINreturned bycase_2(), ensuring a correct result.
Implementation
Expand/collapse the V2.0 accepted code
1 |
|
Implementation detail
The central change is the return statement incase_2():
return total_a == min_val ? LLONG_MIN : total_a - min_val;
This line uses the ternary operator to keep both the special-case check and its handling inside the function, resolving the problem.Improved robustness
TheACcode replaces every hard-coded large or small initialization value, such as1e9, withLLONG_MAXandLLONG_MINfrom the standard library’s<climits>. This removes the dependency on assumptions about the input range and makes the code more general and robust.
P.S. The complete handwritten notes:
Figure legend: The top shows the sample array and its circular layout. “Case 1” means the selection does not cross the cut; “Case 2” means it does. Purple arcs indicate the selected portions in each sketch.
Takeaways
- Handling circular problems: Combining case analysis with a complementary formulation is an effective way to turn this kind of circular-array problem into calculations on a line.
- Boundary cases matter: Special datasets such as all-positive and all-negative arrays need explicit analysis. Constraints such as nonempty can determine correctness precisely at these boundaries.
- A technique for invalid answers: If one branch of an algorithm can produce a logically invalid result, return a value that the final aggregation operation, such as
maxormin, will always discard—for example,LLONG_MINorLLONG_MAX. This avoids complicated checks outside the branch.