Problem:
Score : 1100 points

Problem Statement

Snuke got positive integers s_1,...,s_N from his mother, as a birthday present. There may be duplicate elements.

He will circle some of these N integers. Since he dislikes cubic numbers, he wants to ensure that if both s_i and s_j (i ≠ j) are circled, the product s_is_j is not cubic. For example, when s_1=1,s_2=1,s_3=2,s_4=4, it is not possible to circle both s_1 and s_2 at the same time. It is not possible to circle both s_3 and s_4 at the same time, either.

Find the maximum number of integers that Snuke can circle.

Constraints

1 ≦ N ≦ 10^5

1 ≦ s_i ≦ 10^{10}

All input values are integers.

Input

The input is given from Standard Input in the following format:

N
s_1
:
s_N

Output

Print the maximum number of integers that Snuke can circle.

Sample Input 1

8
1
2
3
4
5
6
7
8

Sample Output 1

6

Snuke can circle 1,2,3,5,6,7.

Sample Input 2

6
2
4
8
16
32
64

Sample Output 2

3

Sample Input 3

10
1
10
100
1000000007
10000000000
1000000009
999999999
999
999
999

Sample Output 3

9

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
class E { static void Main() { new K(); } }
class K
{
	public K()
	{
		var N = int.Parse(Console.ReadLine());
		var ps = GetPrimes(100100);
		var p2 = new Dictionary<long, int>();
		foreach (var p in ps) p2.Add(p * (long)p, p);
		var z = new long[N];
		var cnt = new Dictionary<long, int>();
		var w = new Dictionary<long, long>();
		for (var i = 0; i < N; i++)
		{
			var num = long.Parse(Console.ReadLine());
			var fact = new List<int>();
			var t = 1L;
			for (var j = 0; j < ps.Count; j++)
			{
				var x = ps[j];
				var cube = x * (long)x * x;
				if (cube > num) break;
				if (num % x == 0)
				{
					fact.Add(x);
					while (num % cube == 0) num /= cube;
					if (num % (x * (long)x) == 0) t *= x;
					else if (num % x == 0) t *= x * (long)x;
				}
			}
			z[i] = num;
			if (!w.ContainsKey(z[i]))
			{
				foreach (var p in fact) while (num % p == 0) num /= p;
				var lim = 10000000100L;
				var lim2 = (int)(Math.Sqrt(lim) + 10);
				if (p2.ContainsKey(num)) { if (p2[num] < lim) t *= p2[num]; else t = -1; }
				else { if (num < lim2) t *= num * num; else t = -1; }
				w[z[i]] = t;
				cnt[z[i]] = 0;
			}
			cnt[z[i]]++;
		}
		var sum = 0;
		var set = new HashSet<long>(z);
		var done = new HashSet<long>();
		if (set.Contains(1)) { sum++; set.Remove(1); }
		foreach (var x in set)
		{
			if (done.Contains(x)) continue;
			var y = w[x];
			if (cnt.ContainsKey(y)) sum += Math.Max(cnt[x], cnt[y]);
			else sum += cnt[x];
			done.Add(x);
			done.Add(y);
		}
		Console.WriteLine(sum);
	}
	List<int> GetPrimes(int n)
	{
		var m = (n - 1) >> 1;
		var primes = new List<int>((int)(n / Math.Log(n)));
		primes.Add(2);
		var composites = new bool[m];
		composites[0] = false;
		for (var p = 0; p < m; p++)
			if (!composites[p])
			{
				var pnum = 2 * p + 3;
				primes.Add(pnum);
				for (var k = 3 * p + 3; k < m; k += pnum) composites[k] = true;
			}
		return primes;
	}
}