Skip to content

230B. T-primes

binary search/implementation/math/number theory, 1300, http://codeforces.com/problemset/problem/230/B

We know that prime numbers are positive integers that have exactly two distinct positive divisors. Similarly, we'll call a positive integer t Т-prime, if t has exactly three distinct positive divisors.

You are given an array of n positive integers. For each of them determine whether it is Т-prime or not.

Input

The first line contains a single positive integer, n (1 ≤ n ≤ 10^5^), showing how many numbers are in the array. The next line contains n space-separated integers x~i~ (1 ≤ x~i~ ≤ 10^12^).

Please, do not use the %lld specifier to read or write 64-bit integers in С++. It is advised to use the cin, cout streams or the %I64d specifier.

Output

Print n lines: the i-th line should contain "YES" (without the quotes), if number x~i~ is Т-prime, and "NO" (without the quotes), if it isn't.

Examples

input

3
4 5 6

output

YES
NO
NO

Note

The given test has three numbers. The first number 4 has exactly three divisors — 1, 2 and 4, thus the answer for this number is "YES". The second number 5 has two divisors (1 and 5), and the third number 6 has four divisors (1, 2, 3, 6), hence the answer for them is "NO".

与这个题目类似,都是找平方数优化。01218:THE DRUNK JAILER,http://cs101.openjudge.cn/practice/01218/

这个题目实际上是DP思路。

数论是有趣和优美的数学分支。欧几里得对于素数无穷性的证明在今天看来仍和两千年前一样清晰和优雅。长久以来,计算机都被用来辅助数论研究,有很多精妙的算法能够帮上忙。

求解素数的三种方法,包括:试除法(trial division)、埃氏筛(Sieve of Eratosthenes)、欧拉筛(Sieve of Euler,线性法),https://blog.dotcpp.com/a/69737

数据类型时间复杂度,https://wiki.python.org/moin/TimeComplexity

埃氏筛法,时间复杂度为:O(n*logn)。Python3, Accepted, 1154ms

python
# http://codeforces.com/problemset/problem/230/B

# https://www.geeksforgeeks.org/python-program-for-sieve-of-eratosthenes/
# Python program to print all primes smaller than or equal to 
# n using Sieve of Eratosthenes 

def SieveOfEratosthenes(n, prime): 
    p = 2
    while (p * p <= n): 
      
    	# If prime[p] is not changed, then it is a prime 
    	if (prime[p] == True): 
          
        	# Update all multiples of p 
        	for i in range(p * 2, n+1, p): 
            	prime[i] = False
    	p += 1

n = int(input())
x = [int(i) for i in input().split()]

s = [True]*(10**6+1)

SieveOfEratosthenes(10**6, s)

for i in x:
    if i<4:
        print('NO')
        continue
    elif int(i**0.5)**2 != i:
        print('NO')
        continue
    print(['NO','YES'][s[int(i**0.5)]])
    #if s[int(i**0.5)]:
    #    print('YES')
    #else:
    #    print('NO')

小优化(原因如下,下面用到集合实现),第15行可以写成 for i in range(p * p, n+1, p): 则998ms可以AC.

埃氏筛法,时间复杂度为:O(n*loglogn)。Python3, Accepted, 1558ms

这里有一个小优化,j 从 i * i 而不是从 i + i开始,因为 i*(2~ i-1)在 2~i-1时都已经被筛去,所以从i * i开始。

According to Python wiki: Time complexity, set is implemented as a hash table. So you can expect to lookup/insert/delete in O(1) average. https://stackoverflow.com/questions/7351459/time-complexity-of-python-set-operations

python
n = 1000000
a = [1] * n
s = set() 

#directly add the square of prime into a set, then check if num_input is in set.
for i in range(2,n):
    if a[i]:
        s.add(i*i)
        for j in range(i*i,n,i):
            a[j] = 0

input()
for x in map(int,input().split()):
    print(["NO","YES"][x in s])

埃氏筛法,by 2020fall-cs101, 汪元正, Python3, Accepted, 1340ms

python
a = [1]*(10**6)
a[0] = 0
for i in range(1,10**3,1):
    if a[i]==1:
        for j in range(2*i+1,10**6,i+1):
            a[j]=0

n = int(input())
l = [int(x) for x in input().split()]
for i in range(n):
    m = l[i]
    if m**0.5%1==0:
        r = int(m**0.5)
        if a[r-1]==1:
            print('YES')
        else:
            print('NO')
    else:
        print('NO')

线性筛(欧拉筛),时间复杂度为:O(n)。Python3, Accepted, 998ms。

欧拉筛法(也称为线性筛法)是一种高效的算法,用于在 O(n) 时间复杂度内找到一定范围内所有的素数。相比埃拉托斯特尼筛法,欧拉筛法通过确保每个合数只被其最小的素因子筛除一次,从而避免了重复标记,提高了效率。

欧拉筛法的基本思想

  1. 初始化:创建一个布尔数组 is_prime,初始时所有元素设为 True,表示所有数都是素数。同时创建一个列表 primes,用于存储找到的素数。
  2. 遍历:从 2 开始遍历到 n,对于每个数 i:
    • 如果 is_prime[i]True,则 i 是素数,将其加入 primes 列表。
    • 对于每个已知的素数 p,如果 i * p 不超过 n,将 i * p 标记为合数(设置 is_prime[i * p]False)。
    • 如果 i 能被 p 整除(即 i % p == 0),则停止当前的内层循环。这是因为 i * p 之后的合数会被 i 的更大倍数筛除,不需要重复标记。

代码实现

python
def euler_sieve(n):
    is_prime = [True] * (n + 1)
    primes = []
    for i in range(2, n + 1):
        if is_prime[i]:
            primes.append(i)
        for p in primes:
            if i * p > n:
                break
            is_prime[i * p] = False
            if i % p == 0:
                break
    return primes

# 示例
n = 50
print(euler_sieve(n))

关键点

  • 避免重复标记:通过 if i % p == 0 这个条件,确保每个合数只被其最小的素因子标记一次。
  • 时间复杂度:O(n),每个数只会被标记一次。
  • 空间复杂度:O(n),需要一个布尔数组来记录每个数是否为素数。

优点

  • 高效:时间复杂度为 O(n),适用于处理大规模数据。
  • 简洁:实现相对简单,易于理解和维护。
python
def euler_sieve(n):
    is_prime = [True] * (n + 1)
    is_prime[0] = is_prime[1] = False
    primes = []
    for i in range(2, n + 1):
        if is_prime[i]:
            primes.append(i)
        for p in primes:
            if i * p > n:
                break
            is_prime[i * p] = False
            if i % p == 0:
                break
    return is_prime
 
s = euler_sieve(1000000)
 
input()
for i in map(int,input().split()):
    sqrt_i = i**0.5
    if sqrt_i % 1 == 0:	# 对于浮点数,x % 1 == 0 用于检查 x 是否是一个整数。
        if s[int(sqrt_i)]:
            print('YES')
        else:
            print('NO')
    else:
        print('NO')

线性筛(欧拉筛),时间复杂度为:O(n)。Python3, Accepted, 1808ms。

Python
# https://blog.dotcpp.com/a/69737
# https://blog.csdn.net/xuechen_gemgirl/article/details/79555123
def euler(r):
    prime = [0 for i in range(r+1)]
    common = []
    for i in range(2, r+1):
        if prime[i] == 0:
            common.append(i)
        for j in common:
            if i*j > r:
                break
            prime[i*j] = 1
            if i % j == 0:
                break
    return prime 

s = euler(1000000)
#print(s)

input()
for i in map(int,input().split()):
    if i<4:
        print('NO')
        continue
    elif int(i**0.5)**2 != i:
        print('NO')
        continue
    if s[int(i**0.5)]==0:
        print('YES')
    else:
        print('NO')

Python3, Accepted, 748ms。用到了埃式筛法,内置函数math.sqrt, math.isqrt,set,第8行循环从i*i开始,使用 sys.stdin.read() 一次性读取所有输入,缓存一次性输出。

python
import math

def sieve(limit):
    is_prime = [True] * (limit + 1)
    is_prime[0] = is_prime[1] = False
    for i in range(2, int(math.sqrt(limit)) + 1):
        if is_prime[i]:
            for j in range(i * i, limit + 1, i):
                is_prime[j] = False
    return [i for i in range(limit + 1) if is_prime[i]]

def is_t_prime(x, primes_set):
    if x < 2:
        return False
    root = int(math.isqrt(x))
    return root * root == x and root in primes_set

def main():
    import sys
    input = sys.stdin.read
    data = input().split()
    
    n = int(data[0])
    numbers = list(map(int, data[1:n+1]))
    
    limit = 10**6
    primes = sieve(limit)
    primes_set = set(primes)
    
    results = []
    for number in numbers:
        if is_t_prime(number, primes_set):
            results.append("YES")
        else:
            results.append("NO")
    
    print("\n".join(results))

if __name__ == "__main__":
    main()

可以进一步优化,直接用is_prim列表。Python3, Accepted, 654ms。

python
import math

def sieve(limit):
    is_prime = [True] * (limit + 1)
    is_prime[0] = is_prime[1] = False
    for i in range(2, int(math.sqrt(limit)) + 1):
        if is_prime[i]:
            for j in range(i * i, limit + 1, i):
                is_prime[j] = False
    #return [i for i in range(limit + 1) if is_prime[i]]
    return is_prime

#def is_t_prime(x, primes_set):
def is_t_prime(x, primes_list):
    if x < 2:
        return False
    root = int(math.isqrt(x))
    #return root * root == x and root in primes_set
    return root * root == x and primes_list[root]

def main():
    import sys
    input = sys.stdin.read
    data = input().split()

    n = int(data[0])
    numbers = list(map(int, data[1:n+1]))

    limit = 10**6
    primes = sieve(limit)
    #primes_set = set(primes)

    results = []
    for number in numbers:
        #if is_t_prime(number, primes_set):
        if is_t_prime(number, primes):
            results.append("YES")
        else:
            results.append("NO")

    print("\n".join(results))

if __name__ == "__main__":
    main()