//ProblemD.cpp

#include <iostream>

static std::istream & ip = std::cin;
static std::ostream & op = std::cout;

#if OJ_MYPC
#include <ojio.h>
#endif

#ifndef OPENOJIO
#define OPENOJIO
#endif

#if 1 || DEFINE
/***************************************************************/
typedef unsigned long long u64;
typedef long long s64;

typedef unsigned uint;

#define ABS(x) ((x) > 0 ? (x) : -(x))

#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define MAX(x, y) ((x) > (y) ? (x) : (y))

#define MIN3(x, y, z) MIN(x, MIN(y, z))
#define MAX3(x, y, z) MAX(x, MAX(y, z))

#define FillZero(arr) memset(arr, 0, sizeof(arr));

/***************************************************************/
#endif //1 || DEFINE

#include <string>
#include <vector>
#include <map>
#include <set>
#include <bitset>
#include <queue>
#include <stack>
#include <utility>
#include <algorithm>
#include <iomanip>
#include <cstring>
#include <cmath>
#include <cstdio>

//001
//op << setfill('0') << setw(3) << setiosflags(ios::right) << 1;

//op << fixed << setprecision(20);

using namespace std;

//ProblemD.cpp
#define MAXNUMBER 10000000010L
#define MAXN 100010

#define MAXPRIME 100010 //10^5 (10^10 > 2^32)
#define NUMPRIME 10010

static bool IsPrime[MAXPRIME + 1];
static int ArrayPrimes[NUMPRIME];
static int NumPrimes;
static set<int> SetPrimes;

static void GetPrimes() {
	for (int i = 0; i <= MAXPRIME; ++i) IsPrime[i] = true;
	IsPrime[0] = IsPrime[1] = false;

	IsPrime[2] = true;
	for (int j = 2 * 2; j <= MAXPRIME; j += 2) IsPrime[j] = false;
	for (int i = 3; i <= MAXPRIME; i += 2)
	{
		if (!IsPrime[i]) continue;

		for (int j = i * 2; j <= MAXPRIME; j += i)
		{
			IsPrime[j] = false;
		}
	}

	NumPrimes = 0;
	for (int i = 0; i < sizeof(ArrayPrimes) / sizeof(*ArrayPrimes); ++i) ArrayPrimes[i] = 0;
	SetPrimes.clear();

	for (int i = 1; i <= MAXPRIME; ++i)
		if (IsPrime[i]) {
			SetPrimes.insert(i);
			ArrayPrimes[NumPrimes++] = i;
		}
}

#define CUBE_ROOT 2155
#define SQRT_ROOT 100010

enum GetResult
{
	Normal,
	One,
	Big
};
static GetResult Get(s64 num, s64& norm, s64 &pair)
{
	norm = 1; pair = 1;
	for (auto prim : SetPrimes) {
		if (num == 1) break;
		if (prim > CUBE_ROOT) break;
		int c = 0;
		while (num % prim == 0) { ++c; num /= prim; }

		c %= 3;

		if (c > 0) {
			for (int i = 0; i < c; ++i) norm *= prim;
			for (int i = 0; i < 3 - c; ++i) pair *= prim;
		}

		if (pair > MAXNUMBER) return Big;
	}

	if (num == 1 && norm == 1) return One;

	norm *= num;

	s64 sq = (s64)(sqrt(float(num)) + 0.5f);
	if (sq * sq == num) {
		pair *= sq;
	}
	else {
		if (num > SQRT_ROOT) return Big;
		else {
			pair *= num * num;
		}
	}
	return Normal;
}

int main(int argc, char* argv[])
{
	OPENOJIO;
	GetPrimes();

	int n;
	map<s64, int> norms_count;
	map<s64, s64> norm_pairs;

	ip >> n;
	int nn = 0;
	int cb = 0, c1 = 0;

	for (int i = 0; i < n; ++i) {
		s64 t; ip >> t;

		s64 norm, pair;

		switch (Get(t, norm, pair))
		{
		case Normal:
			++norms_count[norm];
			norm_pairs[norm] = pair;
			break;
		case One:
			++c1;
			break;
		case Big:
			++cb;
			break;
		default:
			throw "Error: ss[nn].type";
		}
	}

	int rst = 0;

	for (auto it : norms_count) {
		const s64& norm = it.first;
		int norm_c = it.second;

		if (norm_c == 0) continue;

		const s64& pair = norm_pairs[norm];
		auto tit = norms_count.find(pair);

		if (tit == norms_count.end()) rst += norm_c;
		else {
			rst += MAX(norm_c, tit->second);
			tit->second = 0;
			it.second = 0;
		}
	}

	rst += cb;
	if (c1 > 0) rst += 1;

	cout << rst << endl;

	return 0;
}
/***************************************************************/


Measured memory_bytes: 11136