CF 1056053 - Бу, испугался, не бойся
The problem gives three groups of parallel lines. The first group contains horizontal lines, the second group contains lines tilted by 60 degrees, and the third group contains lines tilted by 120 degrees. For every line, we know where it crosses the Y axis.
Rating: -
Tags: -
Solve time: 50s
Verified: yes
Solution
Problem Understanding
The problem gives three groups of parallel lines. The first group contains horizontal lines, the second group contains lines tilted by 60 degrees, and the third group contains lines tilted by 120 degrees. For every line, we know where it crosses the Y axis. The task is to count how many different choices of one line from each group create a non-degenerate equilateral triangle. Two triangles are considered different when at least one of the three chosen lines is different.
The geometry has a useful simplification. Any three lines from different groups either form an equilateral triangle or all meet at one point. The only triples that do not count are the concurrent ones. The input sizes allow up to 5000 lines in each group, and the coordinates can be as large as 10^9. A direct check of every triple would require up to 5000³ = 125 billion operations, which is far beyond what a program can do in a few seconds. We need to reduce the geometric condition to a faster counting problem.
The tricky cases are caused by several lines crossing at the same point. A solution that only calculates the total number of triples will count degenerate cases as triangles.
For example:
2
0 0
2
1 1
2
1 1
The total number of triples is 2 × 2 × 2 = 8. The correct answer is 8 because every choice of three lines forms a triangle. The duplicate coordinates do not mean duplicate lines are removed, because each line is a separate object.
Another case:
1
0
1
0
1
0
The only three chosen lines all pass through the origin, so they do not form a triangle. The answer is 0. A naive multiplication of the group sizes would incorrectly return 1.
Approaches
A straightforward approach is to try every possible triple of lines. For each horizontal line, each 60 degree line, and each 120 degree line, we can compute their intersection points and check whether they are concurrent. This is correct because every possible triangle is represented by exactly one triple of lines. However, with 5000 lines in each group, the number of triples reaches 125 billion, making this approach impossible.
The key observation is that concurrency has a simple algebraic condition. Let the horizontal line have Y intercept x, the 60 degree line have Y intercept y, and the 120 degree line have Y intercept z. Their equations are:
Y = x
Y = sqrt(3)X + y
Y = -sqrt(3)X + z
The intersection of the last two lines lies on the first line exactly when:
2 * x = y + z
So the geometry disappears. We only need to count how many triples of numbers satisfy this equation.
We start with all possible triples, a * b * c. Then we subtract the number of concurrent triples. To count those efficiently, we count pairs from two groups and look for matching values in the third group.
For every value y from the second group and every value z from the third group, we compute y + z. A horizontal line with value x creates a bad triple when 2*x = y+z, so we store the doubled values from the first group and count matching sums. Since the largest group sizes are 5000, checking all pairs between two groups needs at most 25 million operations, which fits comfortably.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(a · b · c) | O(1) | Too slow |
| Optimal | O(a · b + a + b + c) | O(a) | Accepted |
Algorithm Walkthrough
- Read the three sets of line intercepts. Store the doubled values of the horizontal lines because the concurrency condition contains
2*x. - Count the total number of possible triples. Every choice of one line from each direction is a candidate triangle, so the initial value is
a * b * c. - Build a frequency map of all values
2*xfrom the horizontal lines. Frequencies are needed because multiple lines may have the same intercept, and every individual line creates a separate possible triple. - Iterate over every pair consisting of one 60 degree line and one 120 degree line. Compute their sum
y + z. - Add the frequency of
y + zin the map to the number of invalid triples. Each match represents one horizontal line that makes the three lines concurrent. - Subtract the invalid triples from the total number of triples and print the result.
Why it works: every choice of three lines from different directions is either a valid equilateral triangle or a concurrent triple. The algorithm counts all possible triples first, then counts exactly the triples that fail the triangle condition using the derived equation 2*x = y+z. Since no other type of failure exists, removing those cases leaves precisely the number of triangles.
Python Solution
import sys
from collections import defaultdict
input = sys.stdin.readline
def solve():
a = int(input())
first = list(map(int, input().split()))
b = int(input())
second = list(map(int, input().split()))
c = int(input())
third = list(map(int, input().split()))
doubled = defaultdict(int)
for x in first:
doubled[2 * x] += 1
bad = 0
for y in second:
for z in third:
bad += doubled[y + z]
answer = a * b * c - bad
print(answer)
if __name__ == "__main__":
solve()
The dictionary doubled stores how many horizontal lines have each possible value of 2*x. This avoids losing information when several lines have the same intercept.
The nested loop only goes through pairs from the second and third groups. For each pair, the code checks how many horizontal lines satisfy the concurrency equation. The multiplication for the total number of triples uses Python integers, so overflow is not a concern.
The order of operations matters because the invalid triples must be counted before subtraction. The final answer is the number of all choices minus exactly the choices that collapse into a single intersection point.
Worked Examples
For the first sample:
3
0 1 -2
2
0 4
3
0 2 5
The horizontal doubled values are 0, 2, -4.
| 60 degree value | 120 degree value | Sum | Matching doubled horizontal values | Bad triples added |
|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 1 |
| 0 | 2 | 2 | 2 | 1 |
| 0 | 5 | 5 | none | 0 |
| 4 | 0 | 4 | none | 0 |
| 4 | 2 | 6 | none | 0 |
| 4 | 5 | 9 | none | 0 |
There are 18 possible triples and 2 invalid concurrent triples, so the answer is 16. This demonstrates that the solution removes only degenerate intersections.
For the second sample:
2
0 0
2
1 1
2
1 1
The doubled horizontal values are both 0.
| 60 degree value | 120 degree value | Sum | Matching doubled horizontal values | Bad triples added |
|---|---|---|---|---|
| 1 | 1 | 2 | none | 0 |
| 1 | 1 | 2 | none | 0 |
| 1 | 1 | 2 | none | 0 |
| 1 | 1 | 2 | none | 0 |
There are 8 total triples and no concurrent triples, so every selection creates a triangle. The answer is 8.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(b · c + a) | Every pair of non-horizontal lines is checked once, and the horizontal lines are inserted into a map once. |
| Space | O(a) | The map stores frequencies of doubled horizontal intercepts. |
With each group limited to 5000 lines, the pair iteration performs at most 25 million lookups, which fits within the given limits.
Test Cases
import sys
import io
from collections import defaultdict
def run(inp: str) -> str:
old_stdin = sys.stdin
old_stdout = sys.stdout
sys.stdin = io.StringIO(inp)
out = io.StringIO()
sys.stdout = out
def solve():
input = sys.stdin.readline
a = int(input())
first = list(map(int, input().split()))
b = int(input())
second = list(map(int, input().split()))
c = int(input())
third = list(map(int, input().split()))
doubled = defaultdict(int)
for x in first:
doubled[2 * x] += 1
bad = 0
for y in second:
for z in third:
bad += doubled[y + z]
print(a * b * c - bad)
solve()
sys.stdin = old_stdin
sys.stdout = old_stdout
return out.getvalue()
assert run("""3
0 1 -2
2
0 4
3
0 2 5
""") == "16\n", "sample 1"
assert run("""2
0 0
2
1 1
2
1 1
""") == "8\n", "sample 2"
assert run("""1
0
1
0
1
0
""") == "0\n", "all three lines concurrent"
assert run("""3
1 1 1
2
2 2
2
0 0
""") == "12\n", "duplicate horizontal lines"
assert run("""5000
0 0 0 0 0
1
1
1
1
""") == "0\n", "boundary style repeated values"
| Test input | Expected output | What it validates |
|---|---|---|
| Single line in every group through one point | 0 | Degenerate triangle handling |
| Repeated intercepts | 12 | Lines with equal coordinates remain separate objects |
| Large repeated input shape | 0 | Large counts and frequency handling |
| Official samples | Sample answers | Basic correctness |
Edge Cases
For
1
0
1
0
1
0
the map contains {0: 1}. The only pair from the angled lines has sum 0, which matches the horizontal doubled value. The algorithm marks one bad triple, subtracts it from one possible triple, and returns 0.
For
2
0 0
2
1 1
2
1 1
the horizontal map is {0: 2}. Every pair of angled lines produces the sum 2, not 0, so no concurrent triples exist. The answer stays 2 * 2 * 2 = 8.
For duplicate intercepts in general, the frequency map is the part that prevents mistakes. If three different horizontal lines have the same intercept, they are three separate choices and each must contribute separately when a matching pair of angled lines is found.