Problem:
Score : 1100 points

Problem Statement

Snuke got positive integers s_1,...,s_N from his mother, as a birthday present. There may be duplicate elements.

He will circle some of these N integers. Since he dislikes cubic numbers, he wants to ensure that if both s_i and s_j (i ≠ j) are circled, the product s_is_j is not cubic. For example, when s_1=1,s_2=1,s_3=2,s_4=4, it is not possible to circle both s_1 and s_2 at the same time. It is not possible to circle both s_3 and s_4 at the same time, either.

Find the maximum number of integers that Snuke can circle.

Constraints

1 ≦ N ≦ 10^5

1 ≦ s_i ≦ 10^{10}

All input values are integers.

Input

The input is given from Standard Input in the following format:

N
s_1
:
s_N

Output

Print the maximum number of integers that Snuke can circle.

Sample Input 1

8
1
2
3
4
5
6
7
8

Sample Output 1

6

Snuke can circle 1,2,3,5,6,7.

Sample Input 2

6
2
4
8
16
32
64

Sample Output 2

3

Sample Input 3

10
1
10
100
1000000007
10000000000
1000000009
999999999
999
999
999

Sample Output 3

9

Solution in Java8 (OpenJDK 1.8.0) (judge verdict: Time Limit Exceeded)

import java.io.*;
import java.util.*;
 
public class Main {
 
    static boolean prime[];
 
    public static void main(String[] args) {
        InputReader in = new InputReader(System.in);
        PrintWriter w = new PrintWriter(System.out);
 
        int n = in.nextInt();
 
        long a[] = new long[n];
        for (int i = 0; i < n; i++)
            a[i] = in.nextLong();
 
        int N = 100100;
        sieve(N);
        int q[] = new int[N + 1];
        long p[] = new long[N + 1];
        long r[] = new long[N + 1];
        int ptr = 0;
        for (int i = 2; i <= N; i++) {
            if (prime[i]) {
                q[ptr] = i;
                r[ptr] = i * 1L * i;
                p[ptr++] = i * 1L * i * 1L * i;
            }
        }
 
        for (int i = 0; i < n; i++) {
            for (int j = 0; p[j] <= a[i]; j++) {
                while (a[i] % p[j] == 0)
                    a[i] /= p[j];
            }
        }
 
        // now we have cube free numbers
        TreeMap<Pair, Integer> map = new TreeMap<Pair, Integer>();
        HashMap<Long, Long> AA = new HashMap<Long, Long>();
        HashMap<Long, Long> BB = new HashMap<Long, Long>();
 
        for (int i = 0; i < n; i++) {
            long A = 1, B = 1;
           
            if (AA.containsKey(a[i])) {
                A = AA.get(a[i]);
                B = BB.get(a[i]);
            } 
            
            else {
                long sav = a[i];
                for (int j = 0; r[j] <= a[i]; j++) {
                    long TT = a[i] / q[j];
                    if (TT * q[j] == a[i]) {
                        long T = a[i] / r[j];
                        if (T * r[j] == a[i]) {
                            B *= q[j];
                            a[i] = T;
                        } else {
                            A *= q[j];
                            a[i] = TT;
                        }
                    }
                }
                if (a[i] != 1)
                    A *= a[i];
                AA.put(sav, A);
                BB.put(sav, B);
            }
            
            Pair P = new Pair(A, B);
            if (!map.containsKey(P))
                map.put(P, 0);
            map.put(P, map.get(P) + 1);
        }
 
        int ans = 0;
        
        for (Pair P : map.keySet()) {
            
            Pair O = new Pair(P.y, P.x);
            if (P.x == 1 && P.y == 1) {
                ans += Math.min(1, map.get(P));
            } 
            
            else if (!map.containsKey(O) || P.x > P.y) {
                int pp = map.get(P);
                int qq = map.containsKey(O) ? map.get(O) : 0;
                ans += Math.max(pp, qq);
            }
        }
 
        w.println(ans);
        w.close();
    }
 
    public static void sieve(int n) {
        prime = new boolean[n + 1];
        Arrays.fill(prime, true);
        prime[0] = prime[1] = false;
 
        for (int i = 2; i * i <= n; i++)
            if (prime[i])
                for (int k = i * i; k <= n; k += i)
                    prime[k] = false;
    }
 
    static class Pair implements Comparable<Pair> {
        long x, y;
 
        Pair(long x, long y) {
            this.x = x;
            this.y = y;
        }
 
        public int compareTo(Pair o) {
            if (x != o.x)
                return Long.compare(x, o.x);
            return Long.compare(y, o.y);
        }
 
        public String toString() {
            return x + " " + y;
        }
    }
 
    static class InputReader {
 
        private final InputStream stream;
        private final byte[] buf = new byte[8192];
        private int curChar, snumChars;
        private SpaceCharFilter filter;
 
        public InputReader(InputStream stream) {
            this.stream = stream;
        }
 
        public int snext() {
            if (snumChars == -1)
                throw new InputMismatchException();
            if (curChar >= snumChars) {
                curChar = 0;
                try {
                    snumChars = stream.read(buf);
                } catch (IOException e) {
                    throw new InputMismatchException();
                }
                if (snumChars <= 0)
                    return -1;
            }
            return buf[curChar++];
        }
 
        public int nextInt() {
            int c = snext();
            while (isSpaceChar(c)) {
                c = snext();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = snext();
            }
            int res = 0;
            do {
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = snext();
            } while (!isSpaceChar(c));
            return res * sgn;
        }
 
        public long nextLong() {
            int c = snext();
            while (isSpaceChar(c)) {
                c = snext();
            }
            long res = 0;
            do { 
                res *= 10;
                res += c - '0';
                c = snext();
            } while (!isSpaceChar(c));
            return res;
        }
 
        public int[] nextIntArray(int n) {
            int a[] = new int[n];
            for (int i = 0; i < n; i++) {
                a[i] = nextInt();
            }
            return a;
        }
        
        public boolean isSpaceChar(int c) {
            if (filter != null)
                return filter.isSpaceChar(c);
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }
 
        public interface SpaceCharFilter {
            public boolean isSpaceChar(int ch);
        }
    }
}