#include <bits/stdc++.h>
#define WHOLE(v) (v).begin(), (v).end()
#define REV_WHOLE(v) (v).rbegin(), (v).rend()
using i64 = int64_t;
using namespace std;
template<size_t I,class H,class...T>struct TupleReaderWriter{static tuple<H,T...> r(istream&i){H v;i>>v;return tuple_cat(tuple<H>(v),TupleReaderWriter<sizeof...(T)-1,T...>::r(i));}static void w(ostream&o,tuple<H,T...>&t,string d){TupleReaderWriter<I-1,H,T...>::w(o,t,d);o<<d<<get<I>(t);}};
template<class H,class...T>struct TupleReaderWriter<0,H,T...>{static tuple<H,T...> r(istream&i){H v;i>>v;return tuple<H>(v);}static void w(ostream&o,tuple<H,T...>&t,string d){o<<get<0>(t);}};
template<class...T>istream&operator>>(istream&i,tuple<T...>&t){t=TupleReaderWriter<sizeof...(T),T...>::r(i);return i;}
template<class...T>ostream&operator<<(ostream&o,tuple<T...>&t){string delim=" ";TupleReaderWriter<sizeof...(T)-1,T...>::w(o,t,delim);return o;}
template<class T>istream&operator>>(istream&i,vector<T>&v){for(auto&x:v)i>>x;return i;}
template<class T>ostream&operator<<(ostream&o,vector<T>&v){string delim="";for(auto&x:v)o<<delim<<x,delim=" ";return o;}
template<class I,class T=iterator_traits<I>>I operator+(I it,int n){for(int i=0;i<n;i++)it++;return it;}
template<class I,class T=iterator_traits<I>>I operator-(I it,int n){for(int i=0;i<n;i++)it--;return it;}
template<class T>using rev_priority_queue=priority_queue<T,vector<T>,greater<T>>;
template<class T>using vector2d=vector<vector<T>>;
struct fixprec{int x;fixprec(int d):x(d){}};
ostream&operator<<(ostream&o,fixprec f){return o<<fixed<<setprecision(f.x);}
void R_YESNO(bool p) { cout << (p ? "YES" : "NO") << endl; }
void R_YesNo(bool p) { cout << (p ? "Yes" : "No") << endl; }

/*!* [prime] *!*/
/*+* 素数生成、素因数分解 *+*/

// 素数列を作る
// N: 上限, v: 出力先
void GetPrimes(i64 N, vector<i64> &v) {
    i64 c = 1;
    for (i64 c = 2; c <= N; c++) {
        bool flag = true;
        i64 d = sqrt(c);
        for (int i = 0; i < v.size(); i++) {
            if (c % v[i] == 0) {
                flag = false;
                break;
            }
            if (d < v[i]) break;
        }
        if (flag) v.push_back(c);
    }
}
// 素因数分解を行う
// N: 対象, p: 素数セット(GetPrimesで取得), m: 因数分解形式のマップ, max_p: 使うpの最大値
i64 Factorize(i64 N, const vector<i64> &p, map<i64, int> &m, i64 max_p = INT64_MAX) {
    for (int i = 0; N != 1 && i < p.size() && p[i] <= max_p; i++) {
        while (N % p[i] == 0) {
            if (!m.count(p[i])) m[p[i]] = 0;
            N /= p[i];
            m[p[i]]++;
        }
    }
    return N;
}

const i64 S_MAX = 1e10;
const i64 SQRT_MAX = 1e5;
const i64 CBRT_MAX = 2.2e3;

using P64 = pair<i64, i64>;

int main() {
    int N;
    cin >> N;
    vector<i64> s(N);
    int ans = 0;
    map<i64, int> small;
    map<i64, i64> inv;
    map<P64, int> huge[2];
    vector<i64> p;
    for(i64 &x : s) cin >> x;
    GetPrimes(SQRT_MAX, p);
    for(i64 x : s) {
        map<i64, int> s;
        // O(s^{1/3})
        i64 y = Factorize(x, p, s, CBRT_MAX);
        i64 z = 1;
        for(auto &e : s) 
            for(int i = 0; i < e.second % 3; i++)
                z *= e.first;
        inv[z] = 1;
        for(auto &e : s)
            for(int i = 0; i < int(3e6 - e.second) % 3; i++)
                inv[z] *= e.first;
        if(y == 1) {
            // 1
            small[z]++;
        } else {
            double sqrt_y = sqrt(y);
            if(sqrt_y == floor(sqrt_y) &&
                    sqrt_y == *lower_bound(WHOLE(p), sqrt_y)) {
                // p^2
                huge[1][{i64(sqrt_y), z}]++;
            } else {
                // pq or p
                huge[0][{y, z}]++;
            }
        }
    }
    for(int b = 0; b < 2; b++) {
        for(auto x : huge[b]) {
            i64 y, z;
            tie(y, z) = x.first;
            if(huge[1 - b].count({y, inv[z]})) {
                if(b) {
                    ans += max(huge[1 - b][{y, inv[z]}], x.second);
                }
            } else {
                ans += x.second;
            }
        }
    }
    for(auto x : small) {
        i64 z = x.first;
        if(z == 1) {
            ans++;
            continue;
        }
        if(small.count(inv[z])) {
            if(z < inv[z]) {
                ans += max(small[inv[z]], x.second);
            }
        } else {
            ans += x.second;
        }
    }
    cout << ans << endl;
}



Measured memory_bytes: 9344