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



Sample input:
8
1
2
3
4
5
6
7
8


Sample output:
6

Submission status: Accepted

Solution code:
import sys
readline = sys.stdin.readline
from collections import Counter
LIMIT = 2200
M = LIMIT**2
prime = [0]*M
for i in range(2, M):
    if prime[i]:
        continue
    for j in range(i, M, i):
        if not prime[j]:
            prime[j] = i


def prsh(N):
    prime = [2]
    for L in range(3,N):
        for p in prime:
            if not L % p:
                break
            if p > L**(1/2):
                prime.append(L)
                break
    return prime

PRIME = prsh(LIMIT)
SP = set(p for p in range(1, M) if prime[p] == p)
SP2 = Counter({p**2: p for p in SP})
MAXS = 10**10
N = int(readline())

L = []

match = Counter()
table = Counter()
for i in range(N):
    s = int(readline())
    ctr = 1
    res = 1
    for p in PRIME:
        if s == 1:
            break
        cnt = 0
        while s%p == 0:
            s //= p
            cnt += 1
        if cnt % 3:
            res *= p**(3 - cnt%3)
            ctr *= p**(cnt%3)
        if res > MAXS:
            res = 0    
    if s != 1:
        ctr *= s
        if s in SP:
            res *= s**2
        elif SP2[s]:
            res *= SP2[s]
        else:
            res = 0
    match[ctr] = res
    table[ctr] += 1

ans = 0
seen = set()
for k, v in table.copy().items():
    if k == 1:
        ans += min(v, 1)
        continue
    if k in seen:
        continue
    ans += max(v, table[match[k]])
    seen.add(match[k])
    seen.add(k)
print(ans)

Submission status: Accepted

Solution code:
"""
Rを立法数とする
a * R と a**2 * R a**1 * R → a**2*R a**1*R a**2*R
3つはなれてるとあかん！！　でも取り除かれてるはずだよな…
→Rを取り除いて後はDP

どうやって立法数を取り除く？
10**3.3まで試し割り？→5secだから間に合うかなぁ


Rを取り除く→10**3.333333以下の素数の3乗で割れるか確かめる

対になるsの導出：
素因数分解→10**5まで試し割(割れて10**5以下になったらdivlis方式に変える)
→巨大素数ばっかりだと死ぬ
2乗して新たに生まれたRを取り除けばok！！！！
→範囲は？10**6.6666以下か？(やばくね？)

sと対になるsでは片方しか取れない(dicで管理するかぁ)
sと対sの中で小さい方に合わせてdicで管理かなぁ
"""
def Sieve(n): #n以下の素数全列挙(O(nloglogn)) retは素数が入ってる。divlisはその数字の素因数が一つ入ってる

    ret = []
    divlis = [-1] * (n+1) #何で割ったかのリスト(初期値は-1)
    
    flag = [True] * (n+1)
    flag[0] = False
    flag[1] = False

    ind = 2
    while ind <= n:

        if flag[ind]:
            ret.append(ind)

            ind2 = ind ** 2

            while ind2 <= n:
                flag[ind2] = False
                divlis[ind2] = ind
                ind2 += ind

        ind += 1

    return ret,divlis


N = int(input())
dic = {}

ret,divlis = Sieve(10**5)
ret2 = []
for i in ret:
    ret2.append(i**2)
div3 = 0

for loop in range(N):

    s = int(input())
    ndic = {}

    for i in ret:

        if i**3 > 10**10:
            break

        while s % i == 0:
            if i not in ndic:
                ndic[i] = 1
            else:
                ndic[i] += 1
            s //= i

    if s in ret2:
        ndic[int(s**0.5)] = 2
    else:
        ndic[s] = 1
    
    S = 1
    T = 1
    #print (ndic)
    for i in ndic:
        S *= i ** (ndic[i] % 3)
        T *= i ** ((-1 * ndic[i]) % 3)

    #print (S,T)

    if S == T:
        div3 += 1
    elif S < T:
        if S not in dic:
            dic[S] = [1,0]
        else:
            dic[S][0] += 1
    else:
        if T not in dic:
            dic[T] = [0,1]
        else:
            dic[T][1] += 1

ans = min(1,div3)

for i in dic:
    ans += max(dic[i])

print (ans)

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline

def primeFactor(N):
    i = 2
    ret = {}
    n = N
    mrFlg = 0
    while i*i <= n:
        k = 0
        while n % i == 0:
            n //= i
            k += 1
        if k: ret[i] = k
        i += 1 + i%2
        if i == 101 and n >= 2**20:
            def findFactorRho(N):
                def gcd(a, b):
                    while b: a, b = b, a % b
                    return a
                def f(x, c):
                    return (x * x + c) % N
                for c in range(1, 99):
                    X, d, j = [2], 1, 0
                    while d == 1:
                        j += 1
                        X.append(f(X[-1], c))
                        X.append(f(X[-1], c))
                        d = gcd(abs(X[2*j]-X[j]), N)
                    if d != N:
                        if isPrimeMR(d):
                            return d
                        elif isPrimeMR(N//d): return N//d
            while n > 1:
                if isPrimeMR(n):
                    ret[n], n = 1, 1
                else:
                    mrFlg = 1
                    j = findFactorRho(n)
                    k = 0
                    while n % j == 0:
                        n //= j
                        k += 1
                    ret[j] = k

    if n > 1: ret[n] = 1
    if mrFlg > 0: ret = {x: ret[x] for x in sorted(ret)}
    return ret

def isPrimeMR(n):
    if n == 2:
        return True
    if n == 1 or n & 1 == 0:
        return False
    d = (n - 1) >> 1
    while d & 1 == 0:
        d >>= 1
    
    L = [2, 7, 61] if n < 1<<32 else [2, 13, 23, 1662803] if n < 1<<40 else [2, 3, 5, 7, 11, 13, 17] if n < 1<<48 else [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
    for a in L:
        t = d
        y = pow(a, t, n)
        while t != n - 1 and y != 1 and y != n - 1:
            y = (y * y) % n
            t <<= 1
        if y != n - 1 and t & 1 == 0:
            return False
    return True

N = int(input())
ans = 0
D = {}
for _ in range(N):
    pf = primeFactor(int(input()))
    a, b = 1, 1
    for p in pf:
        a *= p ** (pf[p] % 3)
        b *= p ** (-pf[p] % 3)
    if a not in D: D[a] = 0
    if a == b:
        if D[a] == 0: ans += 1
    else:
        if b not in D: D[b] = 0
        if D[b] <= D[a]: ans += 1
    D[a] += 1

print(ans)

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 7)

import numpy as np
from collections import Counter

N = int(input())

S = np.array(sys.stdin.readlines(), dtype=np.int64)

U = int(10 ** 3.4)
is_prime = np.zeros(U+1, dtype=np.bool)
is_prime[2] = 1
is_prime[3::2] = 1
for p in range(3,U+1,2):
    if p*p > U:
        break
    if is_prime[p]:
        is_prime[p*p::2*p] = 0

primes = is_prime.nonzero()[0]

# 3乗で割る
for p in primes:
    tr = p*p*p
    while True:
        bl = (S % tr == 0)
        if bl.any():
            S[bl] //= tr
        else:
            break

square_part = np.ones_like(S)
free_part = S.copy() # 厳密には違うが
for p in primes:
    sq = p*p
    bl = (S % sq) == 0
    free_part[bl] //= sq
    square_part[bl] *= p
# 相手が自分より大きいならば必ず正しく計算できている
opposite = free_part * free_part * square_part

x_to_y = dict(zip(S,opposite))

counter = Counter(S)
answer = 0
for x,cx in counter.items():
    if x == 1:
        answer += 1
        continue
    y = x_to_y[x]
    if x > y:
        # とりあえずxを採用しておく
        answer += cx
        continue
    cy = counter[y]
    answer -= cy
    answer += max(cx,cy)

print(answer)

Submission status: Runtime Error

Solution code:
import sys
from subprocess import Popen, PIPE
from itertools import groupby
from collections import Counter

def main():
    sys.stdin.readline()
    S = sys.stdin.read()
    T = []
    inv_dict = {}
    Factors = Popen("factor " + S, stdout=PIPE).communicate()[0].split(b"\n")
    for factors in Factors:
        factors = map(int, factors.split()[1:])
        t = 1
        t_inv = 1
        for f, group in groupby(factors):
            n = len(list(group)) % 3
            if n == 1:
                t *= f
            elif n == 2:
                t_inv *= f
        t, t_inv = t * t_inv * t_inv, t * t * t_inv
        T.append(t)
        inv_dict[t] = t_inv

    counter_T = Counter(T)
    ans = 0
    for t, t_cnt in counter_T.items():
        if t == 1:
            ans += 1
            continue
        t_inv = inv_dict[t]
        t_inv_cnt = counter_T[t_inv]
        if t_cnt > t_inv_cnt or (t_cnt == t_inv_cnt and t > t_inv):
            ans += t_cnt
    print(ans)

main()

Submission status: Runtime Error

Solution code:
def examA():
    S = SI()
    if "W" in S and not "E" in S:
        print("No")
    elif "E" in S and not "W" in S:
        print("No")
    elif "N" in S and not "S" in S:
        print("No")
    elif "S" in S and not "N" in S:
        print("No")
    else:
        print("Yes")
    return

def examB():
    N = I()
    A = [I()for _ in range(N)]
    ans = 0
    for i in range(N-1):
        ans += A[i]//2
        if A[i]%2 and A[i+1]>=1:
            ans += 1
            A[i+1] -= 1
    ans += A[N-1]//2
    print(ans)
    return

def examC():
    N = I()
    A = [I()for _ in range(N)]
    if N==1:
        print(0)
        return
    odd = set()
    for i in range(N):
        if i&1==0:
            odd.add(A[i])
    A.sort()
    ans = 0
    for i in range((N+1)//2):
        if A[i*2] in odd:
            continue
        ans += 1
    print(ans)
    return

def examD():
    def factorization_(a):
        rep = [[]for _ in range(2)]
        pair = []
        for i in range(2,int(10**(10*1/3))+2):
            cur = 0
            while a%i==0:
                cur += 1
                a //= i
            if cur>0:
                cur %= 3
                if cur==0:
                    continue
                rep[0].append((i,cur))
                pair.append((i,3-cur))
        if not rep[0]:
            rep[0].append((0,0))
        rep[1] = a
        rep[0] = tuple(rep[0])

        rep = tuple(rep)
        pair = tuple(pair)
        return rep, pair

    N = I()
    S = [I()for _ in range(N)]
    group = defaultdict(int)
    P = defaultdict(tuple)
    for s in S:
        g,p = factorization_(s)
        group[g] += 1
        P[g[0]] = p
    #print(group)
    G2 = deepcopy(group)
    #print(P)
    ans = 0
    for key,c in group.items():
        rep, rest = key
        pair = rest**2
        if rep==((0,0),) and rest==1:
            ans += 1
        else:
            ans += max(c,G2[(P[rep],pair)])
            G2[(rep,rest)] = 0
            group[(P[rep], pair)] = 0
        #print(ans)
    print(ans)
    return

def examE():
    ans = 0
    print(ans)
    return

def examF():
    ans = 0
    print(ans)
    return

import sys,bisect,itertools,heapq,math,random
from copy import deepcopy
from heapq import heappop,heappush,heapify
from collections import Counter,defaultdict,deque
def I(): return int(sys.stdin.readline())
def LI(): return list(map(int,sys.stdin.readline().split()))
def LSI(): return list(map(str,sys.stdin.readline().split()))
def LS(): return sys.stdin.readline().split()
def SI(): return sys.stdin.readline().strip()
global mod,mod2,inf,alphabet,_ep
mod = 10**9 + 7
mod2 = 998244353
inf = 10**18
_ep = 10**(-12)
alphabet = [chr(ord('a') + i) for i in range(26)]

sys.setrecursionlimit(10**6)

if __name__ == '__main__':
    examD()

"""

"""