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 6output
YES
NO
NONote
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
# 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
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
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) 时间复杂度内找到一定范围内所有的素数。相比埃拉托斯特尼筛法,欧拉筛法通过确保每个合数只被其最小的素因子筛除一次,从而避免了重复标记,提高了效率。
欧拉筛法的基本思想
- 初始化:创建一个布尔数组
is_prime,初始时所有元素设为True,表示所有数都是素数。同时创建一个列表primes,用于存储找到的素数。- 遍历:从 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的更大倍数筛除,不需要重复标记。代码实现
pythondef 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),适用于处理大规模数据。
- 简洁:实现相对简单,易于理解和维护。
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。
# 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() 一次性读取所有输入,缓存一次性输出。
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。
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()