← Home
package main

import (
	"bufio"
	"io"
	"os"
	"strconv"
)

func nextInt(data []byte, idx *int) int {
	n := len(data)
	for *idx < n {
		c := data[*idx]
		if c >= '0' && c <= '9' {
			break
		}
		*idx++
	}
	val := 0
	for *idx < n {
		c := data[*idx]
		if c < '0' || c > '9' {
			break
		}
		val = val*10 + int(c-'0')
		*idx++
	}
	return val
}

func buildSPF(n int) []uint32 {
	spf := make([]uint32, n+1)
	if n < 2 {
		return spf
	}
	primes := make([]int, 0, 700000)
	for i := 2; i <= n; i++ {
		if spf[i] == 0 {
			spf[i] = uint32(i)
			primes = append(primes, i)
		}
		si := int(spf[i])
		limit := n / i
		for j := 0; j < len(primes); j++ {
			p := primes[j]
			if p > si || p > limit {
				break
			}
			spf[p*i] = uint32(p)
		}
	}
	return spf
}

func find(parent []uint32, x int) int {
	for parent[x] != uint32(x) {
		parent[x] = parent[int(parent[x])]
		x = int(parent[x])
	}
	return x
}

func union(parent, size []uint32, a, b int, comps *int) {
	ra := find(parent, a)
	rb := find(parent, b)
	if ra == rb {
		return
	}
	if size[ra] < size[rb] {
		ra, rb = rb, ra
	}
	parent[rb] = uint32(ra)
	size[ra] += size[rb]
	*comps = *comps - 1
}

func main() {
	data, _ := io.ReadAll(os.Stdin)
	ptr := 0
	n := nextInt(data, &ptr)
	vals := make([]int, n)
	maxA := 0
	needSieve := false
	for i := 0; i < n; i++ {
		x := nextInt(data, &ptr)
		vals[i] = x
		if x > maxA {
			maxA = x
		}
		if x > 1 && ((x&1) == 1 || (x&3) == 0) {
			needSieve = true
		}
	}

	w := bufio.NewWriterSize(os.Stdout, 1<<20)
	defer w.Flush()

	if !needSieve {
		w.WriteString(strconv.Itoa(n))
		return
	}

	data = nil

	idxByVal := make([]uint32, maxA+1)
	for i, x := range vals {
		idxByVal[x] = uint32(i + 1)
	}

	spf := buildSPF(maxA)

	parent := make([]uint32, n)
	size := make([]uint32, n)
	for i := 0; i < n; i++ {
		parent[i] = uint32(i)
		size[i] = 1
	}
	comps := n

	for i, x := range vals {
		if x > 1 && (x&1) == 1 {
			temp := x
			var blocks [8]int
			cnt := 0
			for temp > 1 {
				p := int(spf[temp])
				pp := 1
				for temp%p == 0 {
					pp *= p
					temp /= p
				}
				blocks[cnt] = pp
				cnt++
			}
			lim := 1 << cnt
			for mask := 0; mask < lim; mask++ {
				s := 1
				for j := 0; j < cnt; j++ {
					if (mask>>j)&1 != 0 {
						s *= blocks[j]
					}
				}
				t := x / s
				if s >= t {
					continue
				}
				ss := int64(s)
				tt := int64(t)

				even := (tt*tt - ss*ss) >> 1
				if even <= int64(maxA) {
					id := idxByVal[int(even)]
					if id != 0 {
						union(parent, size, i, int(id-1), &comps)
					}
				}

				hyp := (tt*tt + ss*ss) >> 1
				if hyp <= int64(maxA) {
					id := idxByVal[int(hyp)]
					if id != 0 {
						union(parent, size, i, int(id-1), &comps)
					}
				}
			}
		} else if (x & 3) == 0 {
			k := x >> 1
			temp := k
			block2 := 1
			for (temp & 1) == 0 {
				block2 <<= 1
				temp >>= 1
			}

			var blocks [8]int
			cnt := 0
			totalOdd := 1
			for temp > 1 {
				p := int(spf[temp])
				pp := 1
				for temp%p == 0 {
					pp *= p
					temp /= p
				}
				blocks[cnt] = pp
				cnt++
				totalOdd *= pp
			}

			lim := 1 << cnt
			for mask := 0; mask < lim; mask++ {
				prod := 1
				for j := 0; j < cnt; j++ {
					if (mask>>j)&1 != 0 {
						prod *= blocks[j]
					}
				}
				evenFactor := block2 * prod
				oddFactor := totalOdd / prod

				m := evenFactor
				nn := oddFactor
				if m < nn {
					m, nn = nn, m
				}

				mm := int64(m)
				n64 := int64(nn)

				oddLeg := mm*mm - n64*n64
				if oddLeg <= int64(maxA) {
					id := idxByVal[int(oddLeg)]
					if id != 0 {
						union(parent, size, i, int(id-1), &comps)
					}
				}

				hyp := mm*mm + n64*n64
				if hyp <= int64(maxA) {
					id := idxByVal[int(hyp)]
					if id != 0 {
						union(parent, size, i, int(id-1), &comps)
					}
				}
			}
		}
	}

	w.WriteString(strconv.Itoa(comps))
}