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 C# (Mono 4.6.2.0) (judge verdict: Wrong Answer)

using System;
using System.Collections.Generic;
class Solve{
    int N;
    long[] s;
    public Solve(){}
    public static int Main(){
        new Solve().Calc();
        return 0;
    }
    void Calc(){
        getinput();
        List<int> p = new List<int>();
        int pm = 0;
        Map m;
        List<long> e = new List<long>();
        List<long> q = new List<long>();
        {
            int j = 2;
            bool b = true;
            bool[] a = new bool[100001];
            for(int i=0;i<100000;i++){
                a[i] = true;
            }
            while(j<100000){
                if(a[j]){
                    p.Add(j);
                    if(b && (long)(j)*(long)(j)*(long)(j) > 10000000000){
                        pm = p.Count - 1;
                        b = false;
                    }
                    for(int i=2;i*j<100000;i++){
                        a[i*j] = false;
                    }
                }
                j++;
            }
        }
        {
            long[] f = new long[N];
            int count = 1;
            List<int> d = new List<int>();
            for(int i=0;i<N;i++){
                long a = s[i];
                for(int j=0;j<pm;j++){
                    long k = p[j]*p[j]*p[j];
                    while(true){
                        if(a%k == 0){
                            a /= k;
                        }
                        else{
                            break;
                        }
                    }
                }
                f[i] = a;
            }
            Array.Sort(f);
            e.Add(f[0]);
            for(int i=1;i<N;i++){
                if(f[i-1] == f[i]){
                    count++;
                }
                else{
                    d.Add(count);
                    count = 1;
                    e.Add(f[i]);
                }
            }
            d.Add(count);
            m = new Map(e.ToArray(),d.ToArray());
        }
        for(int i=0;i<e.Count;i++){
            long a = e[i];
            long b = 1;
            long c = 1;
            bool y = false;
            int j;
            for(j=0;j<pm;j++){
                if(a%(p[j]*p[j]) == 0){
                    a /= (p[j]*p[j]);
                    if(100000000000/b<p[j]){
                        y = true;
                    }
                    b *= p[j];
                }
                else if(a%p[j] == 0){
                    a /= p[j];
                    if(100000000000/b<p[j]*p[j]){
                        y = true;
                    }
                    b *= (p[j]*p[j]);
                }
            }
            for(;j<p.Count;j++){
                if(p[j]*p[j] >= a){
                    if(p[j]*p[j] == a){
                        c = p[j];
                    }
                    else{
                        if(100000000000/a<a){
                            y = true;
                        }
                        c = a*a;
                    }
                    break;
                }
            }
            if(y || 100000000000/b<c){
                q.Add(-1);
            }
            else{
                q.Add(b*c);
            }
        }
        {
            int count = 0;
            if(e[0] == 1){
                count++;
                for(int i=1;i<e.Count;i++){
                    int y = m.Get(q[i]);
                    if(y == -1){
                        count += m.data[i];
                    }
                    else if(e[i] < q[i]){
                        count += m.data[i] <= y ? y : m.data[i];
                    }
                }
            }
            else{
                for(int i=0;i<e.Count;i++){
                    int y = m.Get(q[i]);
                    if(y == -1){
                        count += m.data[i];
                    }
                    else if(e[i] < q[i]){
                        count += m.data[i] <= y ? y : m.data[i];
                    }
                }
            }
            Console.WriteLine(count);
            for(int i=0;i<q.Count;i++){
                Console.WriteLine(q[i]);
            }
        }
    }
    void getinput(){
        N = int.Parse(Console.ReadLine());
        s = new long[N];
        for(int i=0;i<N;i++){
            s[i] = Int64.Parse(Console.ReadLine());
        }
    }    
}
class Map{
    long[] trees;
    public int[] data;
    int length;
    public Map(long[] t,int[] d){
        trees = t;
        length = trees.Length;
        data = d;
        Array.Sort(trees,(a,b) => Compare(a,b));
    }
    public int Compare(long a,long b){
        //ソートの仕方
        if(a > b){
            return 1;
        }
        else if(a < b){
            return -1;
        }
        else{
            return 0;
        }
    }
    public int Get(long a){
        int min = 0;
        int max = length-1;
        while(min != max){
            if(Compare(a,trees[(min+max)/2]) <= 0){
                max = (min+max)/2;
            }
            else{
                min = (min+max)/2+1;
            }
        }
        if(trees[min] == a){
            return data[min];
        }
        else{
            return -1;
        }
    }
    public void Set(long a,int b){
        int min = 0;
        int max = length-1;
        while(min != max){
            if(Compare(a,trees[(min+max)/2]) <= 0){
                max = (min+max)/2;
            }
            else{
                min = (min+max)/2+1;
            }
        }
        data[min] = b;
    }
}