CF 304A - Pythagorean Theorem II
We need to count how many integer-sided right triangles exist such that all three sides are at most n. A right triangle with sides (a, b, c) satisfies the Pythagorean equation: $a^2+b^2=c^2$$a$$b$$c = sqrt{a^2 + b^2} approx 21.21$$a^2 + b^2 = c^2 approx 225.00 + 225.00 = 450.
CF 304A - Pythagorean Theorem II
Rating: 1200
Tags: brute force, math
Solve time: 2m
Verified: yes
Solution
Problem Understanding
We need to count how many integer-sided right triangles exist such that all three sides are at most n.
A right triangle with sides (a, b, c) satisfies the Pythagorean equation:
$a^2+b^2=c^2$$a$$b$$c = \sqrt{a^2 + b^2} \approx 21.21$$a^2 + b^2 = c^2 \approx 225.00 + 225.00 = 450.00$Adjusting a and b updates the triangle and the derived value of c.abc
The problem restricts the order of the sides:
1 ≤ a ≤ b ≤ c ≤ n
The ordering matters because triangles like (3,4,5) and (4,3,5) should be treated as the same triangle. The condition a ≤ b removes duplicates automatically.
The input contains a single integer n. The output is the number of valid triples (a, b, c) satisfying the equation and the ordering constraints.
The upper bound is only 10^4. That immediately changes the nature of the problem. Even an O(n^2) algorithm performs around 10^8 simple operations in the worst case if implemented carefully in Python, which is still borderline but often acceptable with lightweight arithmetic. An O(n^3) solution is completely impossible because it would require roughly 10^12 iterations.
The main challenge is avoiding unnecessary enumeration of triples.
A subtle edge case appears when duplicate triangles are counted accidentally.
For example:
Input:
5
The only valid triangle is (3,4,5).
The correct answer is:
1
A careless brute-force that loops over all ordered pairs (a,b) without enforcing a ≤ b would count both (3,4,5) and (4,3,5) and incorrectly print 2.
Another easy mistake is forgetting that c must also be at most n.
For example:
Input:
10
The pair (6,8) produces c = 10, which is valid.
But (8,15) produces c = 17, which must not be counted even though it satisfies the equation.
A third pitfall comes from floating point precision. Some implementations compute:
c = int(math.sqrt(a*a + b*b))
and then check whether the equation holds. Floating point rounding can occasionally produce incorrect values for larger numbers. The safe approach is to verify explicitly that:
c * c == a * a + b * b
before counting the triangle.
Approaches
The most direct brute-force solution tries every possible triple (a,b,c).
We loop through all values:
1 ≤ a ≤ b ≤ c ≤ n
and check whether:
$a^2+b^2=c^2$$a$$b$$c = \sqrt{a^2 + b^2} \approx 21.21$$a^2 + b^2 = c^2 \approx 225.00 + 225.00 = 450.00$Adjusting a and b updates the triangle and the derived value of c.abc
This works because the definition of a valid triangle is checked exactly. Nothing is missed and nothing invalid is counted.
The problem is the number of iterations. There are roughly:
$n^3$
possible triples. With n = 10^4, that becomes about 10^12 checks, far beyond the time limit.
The key observation is that once a and b are fixed, the value of c is completely determined.
From the equation:
$c=\sqrt{a^2+b^2}$$a$$b$$c = \sqrt{a^2 + b^2} \approx 21.21$$a^2 + b^2 = c^2 \approx 225.00 + 225.00 = 450.00$Adjusting a and b updates the triangle and the derived value of c.abc
So instead of iterating over three variables, we only iterate over (a,b) and test whether the resulting square root is an integer.
This reduces the search space from cubic to quadratic.
For every pair (a,b) with a ≤ b, we compute:
s = a*a + b*b
c = int(sqrt(s))
If c*c == s and c ≤ n, then we found one valid triangle.
The quadratic approach succeeds because the constraint n ≤ 10^4 allows about 5 × 10^7 lightweight iterations in optimized Python.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(n³) | O(1) | Too slow |
| Optimal | O(n²) | O(1) | Accepted |
Algorithm Walkthrough
- Read the integer
n. - Initialize
answer = 0. - Iterate
afrom1ton.
This chooses the first leg of the triangle.
4. Iterate b from a to n.
Starting from a guarantees a ≤ b, so every triangle is counted exactly once.
5. Compute:
s = a*a + b*b
This is the square of the hypotenuse. 6. Compute:
c = int(s ** 0.5)
We only need to check whether s is a perfect square.
7. Verify both conditions:
c * c == s
c <= n
The first condition confirms that c is an integer.
The second ensures the triangle respects the problem bounds. 8. If both conditions hold, increment the answer. 9. Print the final answer.
Why it works
The algorithm examines every possible ordered pair (a,b) satisfying 1 ≤ a ≤ b ≤ n.
For each pair, there is exactly one possible value of c that could satisfy the Pythagorean equation. The algorithm computes that candidate and checks whether it is a valid integer within bounds.
Every valid triangle appears exactly once because the loop enforces a ≤ b. No invalid triangle can be counted because the equality:
$a^2+b^2=c^2$$a$$b$$c = \sqrt{a^2 + b^2} \approx 21.21$$a^2 + b^2 = c^2 \approx 225.00 + 225.00 = 450.00$Adjusting a and b updates the triangle and the derived value of c.abc
is checked directly.
Python Solution
import sys
input = sys.stdin.readline
n = int(input())
answer = 0
for a in range(1, n + 1):
for b in range(a, n + 1):
s = a * a + b * b
c = int(s ** 0.5)
if c <= n and c * c == s:
answer += 1
print(answer)
The outer loop chooses the first leg a. The inner loop starts from a instead of 1, which removes duplicate orderings automatically.
The variable s stores:
$a^2+b^2$
The code computes the integer square root candidate c using floating point square root and integer conversion. The crucial detail is the validation step:
c * c == s
Without this check, rounding errors could incorrectly classify non-squares as squares.
The condition:
c <= n
prevents counting triangles whose hypotenuse exceeds the limit.
No extra arrays or data structures are required, so the memory usage stays constant.
Worked Examples
Example 1
Input:
5
| a | b | s = a²+b² | c | Valid? | Answer |
|---|---|---|---|---|---|
| 1 | 1 | 2 | 1 | No | 0 |
| 1 | 2 | 5 | 2 | No | 0 |
| 1 | 3 | 10 | 3 | No | 0 |
| 1 | 4 | 17 | 4 | No | 0 |
| 1 | 5 | 26 | 5 | No | 0 |
| 2 | 2 | 8 | 2 | No | 0 |
| 2 | 3 | 13 | 3 | No | 0 |
| 2 | 4 | 20 | 4 | No | 0 |
| 2 | 5 | 29 | 5 | No | 0 |
| 3 | 4 | 25 | 5 | Yes | 1 |
The only valid triple is (3,4,5). The ordering condition avoids counting (4,3,5) separately.
Example 2
Input:
10
| a | b | s | c | Valid? | Answer |
|---|---|---|---|---|---|
| 3 | 4 | 25 | 5 | Yes | 1 |
| 6 | 8 | 100 | 10 | Yes | 2 |
| Remaining pairs | - | - | - | No | 2 |
The valid triangles are (3,4,5) and (6,8,10).
This example demonstrates that multiple scaled versions of a primitive Pythagorean triple are counted separately as long as all sides remain within the limit.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n²) | Two nested loops over a and b |
| Space | O(1) | Only a few integer variables are stored |
With n = 10^4, the algorithm performs roughly fifty million iterations in the worst case. Each iteration only does a few arithmetic operations, which fits comfortably within the limits in Python.
Test Cases
# helper: run solution on input string, return output string
import sys
import io
def solve():
input = sys.stdin.readline
n = int(input())
answer = 0
for a in range(1, n + 1):
for b in range(a, n + 1):
s = a * a + b * b
c = int(s ** 0.5)
if c <= n and c * c == s:
answer += 1
print(answer)
def run(inp: str) -> str:
sys.stdin = io.StringIO(inp)
out = io.StringIO()
backup_stdout = sys.stdout
sys.stdout = out
solve()
sys.stdout = backup_stdout
return out.getvalue()
# provided sample
assert run("5\n") == "1\n", "sample 1"
# minimum input
assert run("1\n") == "0\n", "no triangle possible"
# first valid triangle appears
assert run("3\n") == "0\n", "3-4-5 not fully included"
# exact boundary inclusion
assert run("5\n") == "1\n", "3-4-5 counted"
# multiple triples
assert run("10\n") == "2\n", "3-4-5 and 6-8-10"
# larger case
assert run("25\n") == "8\n", "multiple primitive and scaled triples"
| Test input | Expected output | What it validates |
|---|---|---|
1 |
0 |
Minimum boundary |
3 |
0 |
Hypotenuse exceeds limit |
5 |
1 |
First valid Pythagorean triple |
10 |
2 |
Multiple valid triples |
25 |
8 |
Larger search space and scaling behavior |
Edge Cases
Consider the smallest possible input:
1
The loops only test (1,1).
The algorithm computes:
1² + 1² = 2
Since 2 is not a perfect square, no triangle is counted. The output becomes:
0
This confirms the algorithm correctly handles cases where no valid triangle exists.
Now consider the duplicate-counting issue:
5
A naive implementation that loops independently over all a and b would count both:
(3,4,5)
(4,3,5)
The current algorithm avoids this because the inner loop starts from b = a. Once (3,4) is processed, (4,3) never appears.
Finally, consider a case where the hypotenuse exceeds the limit:
10
The pair (8,15) satisfies the Pythagorean equation because:
$8^2+15^2=17^2$
But 17 > 10, so the condition:
c <= n
rejects it correctly. Without that check, the algorithm would overcount invalid triangles.