// Slower C++ solution:
#include<bits/stdc++.h>

using namespace std;

#define FOR(i, s, e) for(int i = (s); i < (e); i++)

#define FOE(i, s, e) for(int i = (s); i <= (e); i++)

#define FOD(i, s, e) for(int i = (s); i >= (e); i--)

#define ll long long



ll A[100005], prime[10005], prime_3[10005];

int n, m, x, y, z, k, w;

int p[10005];



map<ll, int> M;



void find_prime()

{

	FOE(i, 2, 10000)

	{

		if (p[i] == 1) continue;

		for (int j = i * i; j <= 10000; j += i) p[j] = 1;

	}

	

	FOE(i, 2, 10000) if (p[i] == 0) 

	{

		prime[k] = i;

		prime_3[k++] = 1ll * i * i * i;

	}

}



ll inv(ll x)

{

	ll tmp = x, ret = 1ll;

	

	FOR(i, 0, k)

	{

		if (prime_3[i] > tmp) break;

		y = 0;

		while (tmp % prime[i] == 0) 

		{

			tmp /= prime[i];

			y++;

		}

		

		if (y == 1) ret *= prime[i] * prime[i];

		else if (y == 2) ret *= prime[i];

	

		if (ret > 10000000000ll) return -1;

	}

	

	ll t = (ll)sqrt(tmp);

	if (t * t == tmp) ret *= t;

	else ret *= tmp * tmp;

	

	if (ret > 10000000000ll) return -1;

	return ret;

}



int main ()

{

	find_prime();



	scanf("%d", &n);

	FOR(i, 0, n) 

	{

		scanf("%lld", &A[i]);

		FOR(j, 0, k) while (A[i] % prime_3[j] == 0) A[i] /= prime_3[j];

	}

	

	sort(A, A + n);



	x = 0;

	FOR(i, 0, n) 

	{

		x++;

		if (i == n - 1 || A[i] != A[i + 1])

		{

			M.insert(make_pair(A[i], x));

			x = 0;

		}

	}

	

	//FOR(i, 0, n) printf("%lld ", A[i]); printf("\n");

	

	int ans = 0;

	ll tmp;

	

	FOR(i, 0, n)

	{

		if (A[i] == 1) continue;

		if (i > 0 && A[i] == A[i - 1]) continue;

		

	//	printf("%d %d\n", A[i], M.find(A[i]) -> second);

		

		tmp = inv(A[i]);

		

		if (M.find(tmp) == M.end()) ans += M.find(A[i]) -> second;

		else 

		{

			if (tmp < A[i]) continue;

			ans += max(M.find(A[i]) -> second, M.find(tmp) -> second);

		}

	} 

	

	

	if (A[0] == 1) ans++;

	printf("%d\n", ans);

}


// Faster C++ solution for the same problem (measured speedup: 1.2044151598091595x):
#include<map>

#include<cstdio>

#include<algorithm>

using namespace std;

typedef long long ll;

const int MAX = 2160;

const int MAXN = 100000;

int prm[MAX + 5], pcnt = 0;

bool is_prm[MAX + 5];

void init() {

	for(int i=2;i<=MAX;i++) {

		if( !is_prm[i] )

			prm[++pcnt] = i;

		for(int j=1;i*prm[j]<=MAX;j++) {

			is_prm[i*prm[j]] = true;

			if( i % prm[j] == 0 ) break;

		}

	}

}

ll s[MAXN + 5], a[MAXN + 5], b[MAXN + 5];

ll IsSqr(ll x) {

	ll le = 1, ri = 100000;

	while( le < ri ) {

		ll mid = (le + ri) >> 1;

		if( mid * mid >= x ) ri = mid;

		else le = mid + 1;

	}

	return (ri * ri == x) ? ri : 0;

}

int siz[2*MAXN + 5];

map<ll, int>mp;

int main() {

	init(); int N;

	scanf("%d", &N);

	int ans = 0, flag = false;

	for(int i=1;i<=N;i++) {

		a[i] = b[i] = 1;

		scanf("%lld", &s[i]);

		for(int j=1;j<=pcnt;j++) {

			int cnt = 0;

			while( s[i] % prm[j] == 0 ) {

				cnt++;

				s[i] /= prm[j];

			}

			cnt %= 3;

			if( cnt == 1 ) {

				a[i] *= prm[j];

				b[i] *= prm[j] * prm[j];

			}

			else if( cnt == 2 ) {

				a[i] *= prm[j] * prm[j];

				b[i] *= prm[j];

			}

		}

		if( IsSqr(s[i]) ) {

			a[i] *= s[i];

			b[i] *= IsSqr(s[i]);

		}

		else {

			a[i] *= s[i];

			b[i] *= s[i] * s[i];

		}

		if( !flag && a[i] == 1 && b[i] == 1 )

			flag = true;

	}

	for(int i=1;i<=N;i++) {

		if( a[i] == 1 && b[i] == 1 ) continue;

		if( mp.count(a[i]) )

			siz[mp[a[i]]]++;

		else {

			mp[a[i]] = i;

			mp[b[i]] = i+N;

			siz[i]++;

		}

	}

	for(int i=1;i<=N;i++) {

		if( mp[a[i]] == i )

			ans += max(siz[i], siz[i+N]);

	}

	if( flag ) ans++;

	printf("%d\n", ans);

}