import math
def count_parallelograms():
count = 0
n = 500
# iterate through all distinct side lengths a, b
# use the constraint: a + b < n
for a in range(2, n):
for b in range(1, a): # b < a ensures distinctness
if a + b >= n:
break
# Condition: a and b must be relatively prime
if math.gcd(a, b) != 1:
continue
# Parallelogram Law: d1^2 + d2^2 = 2(a^2 + b^2)
S = 2 * (a * a + b * b)
# iterate through possible integer values for diagonal d1
# constraints on d1:
# 1) triangle Inequality: |a - b| < d1 < a + b
# 2) to avoid double counting and ensure d2 exists: d1 <= sqrt(S/2)
lower_bound = a - b + 1
upper_bound = int(math.isqrt(S // 2))
for d1 in range(lower_bound, upper_bound + 1):
# check if d2 is an integer
d2_sq = S - d1 * d1
d2 = math.isqrt(d2_sq)
if d2 * d2 != d2_sq:
continue
# we have integer diagonals d1, d2.
# now check for Integer Area using Heron's Formula on triangle (a, b, d1)
# semiperimeter s must be integer for area to be integer => Perimeter even
if (a + b + d1) % 2 != 0:
continue
s = (a + b + d1) // 2
# area squared = s(s-a)(s-b)(s-d1)
area_sq = s * (s - a) * (s - b) * (s - d1)
if area_sq > 0:
root_area = math.isqrt(area_sq)
if root_area * root_area == area_sq:
# All conditions met: integer sides, diagonals, and area
count += 1
# optional: Print found parallelograms
# print(f"Sides: ({a}, {b}), Diagonals: ({d1}, {d2}), Area: {root_area * 2}")
return count
print(count_parallelograms())
aW1wb3J0IG1hdGgKCmRlZiBjb3VudF9wYXJhbGxlbG9ncmFtcygpOgogICAgY291bnQgPSAwCiAgICBuID0gNTAwCiAgICAjIGl0ZXJhdGUgdGhyb3VnaCBhbGwgZGlzdGluY3Qgc2lkZSBsZW5ndGhzIGEsIGIKICAgICMgdXNlIHRoZSBjb25zdHJhaW50OiBhICsgYiA8IG4KICAgIGZvciBhIGluIHJhbmdlKDIsIG4pOgogICAgICAgIGZvciBiIGluIHJhbmdlKDEsIGEpOiAjIGIgPCBhIGVuc3VyZXMgZGlzdGluY3RuZXNzCiAgICAgICAgICAgIGlmIGEgKyBiID49IG46CiAgICAgICAgICAgICAgICBicmVhawogICAgICAgICAgICAKICAgICAgICAgICAgIyBDb25kaXRpb246IGEgYW5kIGIgbXVzdCBiZSByZWxhdGl2ZWx5IHByaW1lCiAgICAgICAgICAgIGlmIG1hdGguZ2NkKGEsIGIpICE9IDE6CiAgICAgICAgICAgICAgICBjb250aW51ZQogICAgICAgICAgICAKICAgICAgICAgICAgIyBQYXJhbGxlbG9ncmFtIExhdzogZDFeMiArIGQyXjIgPSAyKGFeMiArIGJeMikKICAgICAgICAgICAgUyA9IDIgKiAoYSAqIGEgKyBiICogYikKICAgICAgICAgICAgCiAgICAgICAgICAgICMgaXRlcmF0ZSB0aHJvdWdoIHBvc3NpYmxlIGludGVnZXIgdmFsdWVzIGZvciBkaWFnb25hbCBkMQogICAgICAgICAgICAjIGNvbnN0cmFpbnRzIG9uIGQxOgogICAgICAgICAgICAjIDEpIHRyaWFuZ2xlIEluZXF1YWxpdHk6IHxhIC0gYnwgPCBkMSA8IGEgKyBiCiAgICAgICAgICAgICMgMikgdG8gYXZvaWQgZG91YmxlIGNvdW50aW5nIGFuZCBlbnN1cmUgZDIgZXhpc3RzOiBkMSA8PSBzcXJ0KFMvMikKICAgICAgICAgICAgbG93ZXJfYm91bmQgPSBhIC0gYiArIDEKICAgICAgICAgICAgdXBwZXJfYm91bmQgPSBpbnQobWF0aC5pc3FydChTIC8vIDIpKQogICAgICAgICAgICAKICAgICAgICAgICAgZm9yIGQxIGluIHJhbmdlKGxvd2VyX2JvdW5kLCB1cHBlcl9ib3VuZCArIDEpOgogICAgICAgICAgICAgICAgIyBjaGVjayBpZiBkMiBpcyBhbiBpbnRlZ2VyCiAgICAgICAgICAgICAgICBkMl9zcSA9IFMgLSBkMSAqIGQxCiAgICAgICAgICAgICAgICBkMiA9IG1hdGguaXNxcnQoZDJfc3EpCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIGlmIGQyICogZDIgIT0gZDJfc3E6CiAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgIyB3ZSBoYXZlIGludGVnZXIgZGlhZ29uYWxzIGQxLCBkMi4KICAgICAgICAgICAgICAgICMgbm93IGNoZWNrIGZvciBJbnRlZ2VyIEFyZWEgdXNpbmcgSGVyb24ncyBGb3JtdWxhIG9uIHRyaWFuZ2xlIChhLCBiLCBkMSkKICAgICAgICAgICAgICAgICMgc2VtaXBlcmltZXRlciBzIG11c3QgYmUgaW50ZWdlciBmb3IgYXJlYSB0byBiZSBpbnRlZ2VyID0+IFBlcmltZXRlciBldmVuCiAgICAgICAgICAgICAgICBpZiAoYSArIGIgKyBkMSkgJSAyICE9IDA6CiAgICAgICAgICAgICAgICAgICAgY29udGludWUKICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIHMgPSAoYSArIGIgKyBkMSkgLy8gMgogICAgICAgICAgICAgICAgIyBhcmVhIHNxdWFyZWQgPSBzKHMtYSkocy1iKShzLWQxKQogICAgICAgICAgICAgICAgYXJlYV9zcSA9IHMgKiAocyAtIGEpICogKHMgLSBiKSAqIChzIC0gZDEpCiAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgIGlmIGFyZWFfc3EgPiAwOgogICAgICAgICAgICAgICAgICAgIHJvb3RfYXJlYSA9IG1hdGguaXNxcnQoYXJlYV9zcSkKICAgICAgICAgICAgICAgICAgICBpZiByb290X2FyZWEgKiByb290X2FyZWEgPT0gYXJlYV9zcToKICAgICAgICAgICAgICAgICAgICAgICAgIyBBbGwgY29uZGl0aW9ucyBtZXQ6IGludGVnZXIgc2lkZXMsIGRpYWdvbmFscywgYW5kIGFyZWEKICAgICAgICAgICAgICAgICAgICAgICAgY291bnQgKz0gMQogICAgICAgICAgICAgICAgICAgICAgICAjIG9wdGlvbmFsOiBQcmludCBmb3VuZCBwYXJhbGxlbG9ncmFtcwogICAgICAgICAgICAgICAgICAgICAgICAjIHByaW50KGYiU2lkZXM6ICh7YX0sIHtifSksIERpYWdvbmFsczogKHtkMX0sIHtkMn0pLCBBcmVhOiB7cm9vdF9hcmVhICogMn0iKQoKICAgIHJldHVybiBjb3VudAoKcHJpbnQoY291bnRfcGFyYWxsZWxvZ3JhbXMoKSk=