// Slower C++ solution:
#include<cstdio>

#include<cstring>

#include<algorithm>

#include<vector>

#include<map>

#include<cmath>

#define MAXN 100000

#define MAXV 20000

using namespace std;

typedef long long LL;

vector<int> prime;

LL seq[MAXN+5],a[MAXN+5],b[MAXN+5];

bool vis[MAXV+5];

map<LL,int> mp;

void prepare()

{

	for(int i=2;i<=MAXV;i++)

	{

		if(vis[i]==false)

			prime.push_back(i);

		for(int j=0;1LL*prime[j]*i<=MAXV;j++)

		{

			vis[i*prime[j]]=true;

			if(i%prime[j]==0)

				break;

		}

	}

}

void Work(int i,LL x)

{

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

	for(int j=0;1LL*prime[j]*prime[j]*prime[j]<=x;j++)

	{

		LL t1=prime[j],t2=1LL*prime[j]*prime[j],t3=1LL*prime[j]*prime[j]*prime[j];

		while(x%t3==0)	x/=t3;

		if(x%t2==0)			a[i]*=t2,b[i]*=t1;

		else if(x%t1==0)	a[i]*=t1,b[i]*=t2;

		while(x%t1==0)	x/=t1;

	}

	if(x!=1LL)

	{

		LL t=(LL)sqrt(x);

		if(t*t==x)	a[i]*=x,b[i]*=t;

		else		a[i]*=x,b[i]*=x*x;

	}

}

int main()

{

//	freopen("anticube.in","r",stdin);

//	freopen("anticube.out","w",stdout);

	prepare();

	int N;

	scanf("%d",&N);

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

	{

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

		Work(i,seq[i]);

		mp[a[i]]++;

	}

	int ans=0;

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

		if(mp.find(a[i])!=mp.end())

		{

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

			{

				ans++;

				mp.erase(mp.find(a[i]));

			}

			else

			{

				int ansn=mp[a[i]];

				mp.erase(mp.find(a[i]));

				if(mp.find(b[i])!=mp.end())

				{

					ansn=max(ansn,mp[b[i]]);

					mp.erase(mp.find(b[i]));

				}

				ans+=ansn;

			}

		}

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

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 1.1409004195529882x):
#include <bits/stdc++.h>



using namespace std;



#ifdef Lin1043

    #define DEBUG(msg, ...) printf("(%s #%d) " msg, __FUNCTION__, __LINE__, __VA_ARGS__)

    #define massert(...) assert(...)

#else

    #define DEBUG(...)

    #define massert(...)

#endif



#define rep(i , l , r) for(int i = (l) , ___ = (r) ; i <= ___ ; ++i )

#define per(i , r , l) for(int i = (r) , ___ = (l) ; i >= ___ ; --i )



struct iopener

{

    iopener()

    {

#ifdef Lin1043

        freopen("./in" , "r" , stdin);

#endif

    }

} iop;



typedef long long LL;



template<typename T>inline bool chkmin(T &x , const T &y) { return x > y ? (x = y , 1) : 0; }

template<typename T>inline bool chkmax(T &x , const T &y) { return x < y ? (x = y , 1) : 0; }



template<typename T>inline T read(T &f)

{

    f = 0; int x = 1 ; char c = getchar();

    while(!isdigit(c)) x = (c == '-' ? -1 : 1) , c = getchar();

    while(isdigit(c)) (f *= 10) += c & 15 , c = getchar();

    return f = x * f;

}



const int N = 100000 + 5;



int vis[N];



vector<int> pri;



void sieve()

{

    rep(i , 2 , 2300)

    {

        if(!vis[i])

            pri.push_back(i);

        for(int x : pri)

        {

            if(i * x > 2300) break ;

            vis[i * x] = 1;

            if(i % x == 0) break ;

        }

    }

}



int n ; LL A[N] , Ans;



LL L[N] , R[N];



map<LL , int> G;



int check(LL x)

{

    LL v = sqrt(x);

    return v * v == x;

}



int main()

{

    read(n) , sieve();

    rep(i , 1 , n) read(A[i]);

    rep(i , 1 , n)

    {

        LL x = A[i];

        for(int d : pri)

        {

            LL v = 1ll * d * d * d;

            if(v > x) break ;

            while(x % v == 0) x /= v;

        }

        G[x]++ , L[i] = x;

        LL y = 1;

        for(int d : pri)

        {

            if(1ll * d * d * d > x) break ;

            if(x % d == 0)

            {

                y *= (x % (1ll * d * d) == 0 ? d : 1ll * d * d);

                while(x % d == 0) x /= d;

            }

        }

        y *= check(x) ? sqrt(x) : x * x;

        R[i] = y;

    }

    if(G[1])

        Ans += 1 , G[1] = 0;

    rep(i , 1 , n)

        Ans += max(G[L[i]] , G[R[i]]) , G[L[i]] = G[R[i]] = 0;

    cout << Ans << endl;

    return 0;

}