// Original C++ solution (slower):
#include<cstdio>

#include<cstring>

#include<cmath>

#include<map>

#include<algorithm>

using namespace std;

const long long MAXN=100005,MAXP=21000;



long long prime[MAXP],pcnt;

bool npr[MAXP];



void LinerSieve()

{

	npr[1]=true;

	for(long long i=2;i<MAXP;i++)

	{

		if(!npr[i])

			prime[++pcnt]=i;

		for(long long j=1;j<=pcnt&&prime[j]*i<MAXP;j++)

		{

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

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

				break;

		}

	}

}

long long ans;

map<long long,long long> cnt;

long long n,A[MAXN];

long long F(long long x)

{

	long long res=1;

	for(long long j=1;j<=pcnt&&prime[j]*prime[j]*prime[j]<=x;j++)

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

		{

			long long cnt=0;

			while(x%prime[j]==0)

				x/=prime[j],cnt++;

			cnt%=3;

			for(long long k=1;k<=cnt;k++)

				res*=prime[j];

		}

	if(x!=1)

		res*=x;

	return res;

}



int main()

{



	LinerSieve();

    scanf("%lld",&n);

    for(long long i=1;i<=n;i++)

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

	for(long long i=1;i<=n;i++)

	{

		A[i]=F(A[i]);

		cnt[A[i]]++;

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

	}

	

	bool flag=false;

	for(long long i=1;i<=n;i++)

	{

		if(A[i]==1)

			flag=true;

		else if(cnt[A[i]])

		{

			long long tmp=floor(sqrt(A[i])+0.5);

			long long y;

			if(tmp*tmp==A[i])

				y=tmp;

			else

				y=A[i]*A[i];

			y=F(y);

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

			if(cnt.count(y))

			{

				//puts("1");

				ans+=max(cnt[y],cnt[A[i]]);

				cnt[y]=cnt[A[i]]=0;

			}

			else

			{

				ans+=cnt[A[i]];

				cnt[A[i]]=0;

			}

		}

	}

	if(flag)

		ans++;

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



    fclose(stdin);

    fclose(stdout);

    return 0;

}


// Optimized solution to the same problem (faster):
#include <map>

#include <cmath>

#include <cstdio>



typedef long long LL;



const int MAXN = 1e5 + 5;



template<typename _T>

void read( _T &x )

{

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

	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}

	while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}

	x *= f;

}



template<typename _T>

void write( _T x )

{

	if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }

	if( 9 < x ){ write( x / 10 ); }

	putchar( x % 10 + '0' );

}



template<typename _T>

_T MAX( const _T a, const _T b )

{

	return a > b ? a : b;

}



std :: map<LL, int> mp;



LL a[MAXN], oppo[MAXN];

LL pw2[MAXN], pw3[MAXN];



int prime[MAXN], pn;

int N;



bool isPrime[MAXN];



void EulerSieve( const int siz )

{

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

	{

		if( ! isPrime[i] ) prime[++ pn] = i;

		for( int j = 1 ; j <= pn && 1ll * i * prime[j] <= siz ; j ++ )

		{

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

			if( ! ( i % prime[j] ) ) break;

		}

	}

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

		pw2[i] = 1ll * prime[i] * prime[i], pw3[i] = 1ll * pw2[i] * prime[i];

}



int main()

{

	bool flg = false;

	read( N ); EulerSieve( 3000 );

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

	{

		read( a[i] );

		for( int k = 1 ; k <= pn && pw3[k] <= a[i] ; k ++ )

			while( ! ( a[i] % pw3[k] ) )

				a[i] /= pw3[k];

		if( a[i] == 1 ) flg = true, mp[a[i]] = -1;

		else

		{

			mp[a[i]] ++;

			LL tmp = a[i];

			int tot = 0, indx; LL rest = 1;

			for( int k = 1 ; k <= pn && prime[k] <= tmp ; k ++ )

				if( ! ( tmp % prime[k] ))

				{

					tot ++, indx = 0;

					while( ! ( tmp % prime[k] ) )

						indx ++, tmp /= prime[k];

					if( indx & 1 ) rest = 1ll * rest * pw2[k];

					else rest = 1ll * rest * prime[k];

				}

			int t = sqrt( tmp );

			if( 1ll * t * t == tmp ) oppo[i] = 1ll * t * rest;

			else oppo[i] = ( tmp <= 1e5 ? rest * tmp * tmp : 0 );

		}

	}

	int ans = 0;

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

		if( ~ mp[a[i]] )

			ans += MAX( mp[a[i]], mp[oppo[i]] ),

			mp[a[i]] = mp[oppo[i]] = -1;

	write( ans + flg ), putchar( '\n' );

	return 0;

}

// Fastest known solution for this problem: