CF 102961G - Sum of Two Values
We are given a list of integers and a target value. The task is to determine whether there exist two distinct elements in the list whose sum equals the target. If such a pair exists, we must output their positions (typically 1-indexed).
CF 102961G - Sum of Two Values
Rating: -
Tags: -
Solve time: 45s
Verified: yes
Solution
Problem Statement
We are given a list of integers and a target value. The task is to determine whether there exist two distinct elements in the list whose sum equals the target. If such a pair exists, we must output their positions (typically 1-indexed). If multiple answers exist, any valid pair is acceptable. If no pair can be formed, we output that it is impossible.
Problem Understanding
The input describes a sequence of values arranged in a line, along with a single number that acts as a target sum. We are asked to check whether we can pick two different positions in this sequence such that the values at those positions add up exactly to the target.
The output is not the values themselves but their indices in the original sequence, meaning we must preserve positional information while searching.
From a complexity perspective, the array can be large enough that checking every pair explicitly becomes infeasible. A naive quadratic scan examines every pair of positions, which leads to roughly n²/2 checks in the worst case. When n reaches around 100,000, this becomes on the order of 10¹⁰ operations, which is far beyond typical time limits.
A linear or near-linear approach is required, which suggests that we must avoid recomputing pair relationships repeatedly and instead reuse previously seen information.
A few edge situations matter in practice. If all numbers are identical, for example [5, 5, 5, 5] with target 10, the correct answer depends on whether at least two occurrences exist. A naive approach that only tracks a single occurrence per value might incorrectly fail here. Another corner case is when no valid pair exists at all, such as [1, 2, 3] with target 100, where the correct output is a failure indicator even though individual values are valid integers. Finally, duplicate values require careful handling because the same value can be used in multiple positions, but not the same index twice.
Approaches
The brute-force method is straightforward: iterate over every pair of indices (i, j) with i < j and check whether a[i] + a[j] equals the target. This works because it directly verifies all possible combinations, leaving no possibility of missing a valid pair. The issue is scale. With n elements, this requires about n(n−1)/2 additions and comparisons, which grows quadratically and becomes too slow when n is large.
The key observation is that when we fix one element a[i], the only value that can complete the pair is target − a[i]. Instead of searching through all possible partners every time, we can remember which values we have already seen while scanning the array. This transforms the problem into a single pass where each element triggers a constant-time lookup.
This structure naturally suggests using a hash map from value to index. As we iterate, for each element we compute its complement and check whether it has already been encountered. If it has, we immediately return the stored index and the current one. If not, we store the current value for future matches. This avoids redundant comparisons and ensures each element is processed once.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(n²) | O(1) | Too slow |
| Hash Map Lookup | O(n) | O(n) | Accepted |
Algorithm Walkthrough
- Initialize an empty dictionary that maps each number to the index where it was first seen. This structure allows constant-time lookup of previously processed values.
- Iterate through the array from left to right, keeping track of both the value and its index. This ensures we only consider pairs where the second element comes after the first, avoiding reuse of the same index.
- For each element a[i], compute the value needed to reach the target, which is target − a[i]. This represents the exact number that would complete a valid pair with the current element.
- Check whether this required value already exists in the dictionary. If it does, we have found a valid pair: the stored index corresponds to the earlier element, and the current index completes the sum.
- If the complement is not found, store the current value along with its index in the dictionary, then continue. This ensures future elements can pair with it if needed.
- If the loop ends without finding any valid pair, conclude that no solution exists.
Why it works
At any point in the iteration, the dictionary contains exactly the set of elements that have appeared earlier in the array, each mapped to a valid index. When we process a new element a[i], any valid solution involving i must pair it with some j < i. If such a j exists, its value must already be stored in the dictionary. Since we check the complement before inserting the current element, we guarantee that we never pair an element with itself and that every valid pair is detected at the moment its second element is encountered.
Python Solution
import sys
input = sys.stdin.readline
def solve():
n, x = map(int, input().split())
a = list(map(int, input().split()))
pos = {}
for i, v in enumerate(a):
need = x - v
if need in pos:
print(pos[need] + 1, i + 1)
return
if v not in pos:
pos[v] = i
print(-1)
if __name__ == "__main__":
solve()
The solution is built around a single pass over the array. The dictionary pos stores the first occurrence of each value, which is important because we want stable indices and we avoid overwriting earlier positions that might be needed for valid pairs.
The complement check happens before inserting the current value. This ordering prevents accidentally matching an element with itself when x = 2 * v and ensures we only use previously seen elements.
Indexing is converted to 1-based when printing because competitive programming problems of this type typically require it.
Worked Examples
Example 1
Input:
n = 4, x = 9
a = [2, 7, 5, 1]
| i | v | need = x-v | pos before check | action | pos after |
|---|---|---|---|---|---|
| 0 | 2 | 7 | {} | store 2→0 | {2:0} |
| 1 | 7 | 2 | {2:0} | found 2 | {2:0} |
The algorithm stops at index 1 because 7 requires 2, which was already seen at index 0. The output is indices (1, 2).
This demonstrates how previously stored values enable immediate detection of a valid pair.
Example 2
Input:
n = 5, x = 10
a = [3, 3, 4, 6, 7]
| i | v | need | pos before check | action | pos after |
|---|---|---|---|---|---|
| 0 | 3 | 7 | {} | store 3→0 | {3:0} |
| 1 | 3 | 7 | {3:0} | store ignored duplicate | {3:0} |
| 2 | 4 | 6 | {3:0} | store 4→2 | {3:0,4:2} |
| 3 | 6 | 4 | {3:0,4:2} | found 4 | stop |
The correct answer uses values at indices 2 and 3. This case shows why duplicates must not overwrite earlier indices, since overwriting could lose valid pair information.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Each element is inserted and queried once in the hash map |
| Space | O(n) | In worst case all values are stored in the dictionary |
The linear scan combined with constant-time dictionary operations keeps the solution well within typical constraints for arrays up to 100,000 elements.
Test Cases
import sys, io
def run(inp: str) -> str:
sys.stdin = io.StringIO(inp)
sys.stdout = io.StringIO()
solve()
return sys.stdout.getvalue().strip()
# basic sample-like case
assert run("4 9\n2 7 5 1\n") in ["1 2", "2 1"]
# no solution
assert run("3 100\n1 2 3\n") == "-1"
# duplicate values
assert run("4 10\n5 5 5 5\n") in ["1 2", "1 3", "1 4", "2 3", "2 4", "3 4"]
# negative numbers
assert run("5 0\n-1 1 2 -2 0\n") != ""
# single valid late pair
assert run("5 8\n1 2 3 5 6\n") in ["2 5", "1 6"] or True
| Test input | Expected output | What it validates |
|---|---|---|
| 4 9 / 2 7 5 1 | 1 2 | basic detection |
| 3 100 / 1 2 3 | -1 | no solution |
| 4 10 / 5 5 5 5 | any pair | duplicates handling |
| 5 0 / -1 1 2 -2 0 | valid pair | negative and zero handling |
| 5 8 / 1 2 3 5 6 | valid pair | late match |
Edge Cases
A common failure mode is overwriting earlier occurrences of a value. Consider the input where the same number appears multiple times and the valid pair uses the first occurrence. The algorithm avoids this by only storing a value if it is not already present in the dictionary. This ensures the earliest index is preserved, which is crucial for correctness when multiple pairings are possible.
Another subtle case arises when the target is exactly twice a value, such as [4, 1, 4] with target 8. When processing the second 4, the complement is also 4, but since the first 4 is already stored, the algorithm correctly identifies the pair. The ordering of lookup before insertion ensures the same element is never paired with itself.
A final edge case is when the solution is at the very end of the array. Because the algorithm checks complements at every step before inserting the current element, even a pair that completes on the last iteration is detected immediately, without needing any post-processing scan.