【数论】Acwing质数与约数

质数
  • 质数的判定(试除法)

除了开方的数,其他因数都是成对出现的

def is_prime(x):
	if(x < 2) return False
	for i in range(2, int(x/i) + 1):
        if (x % iW == 0):
            return False
    return True
  • 分解质因数
def divide(x):
    for i in range(2, int(x/i) + 1):
        if(x % i == 0):
            s = 0
            while (x % i == 0):
            	x //= i
                s += 1
  • 筛质法

简单做法:从1~n的数字将倍数都删除

埃氏筛法

优化:只需要对质数的倍数进行删除,合数的倍数在质数的处理过程也会被删除(唯一分解定理)

质数定理:1~n中有 n l n n \frac{n}{lnn} lnnn个质数

缺点:一个合数可能被多个数筛掉,存在重复计算

st = [1] * n
primes = []
for i in range(2, n+1):
    if st[i]: # 1表示还没被筛掉,是质数
        primes.append(i)
        for j in range(i, n+1, i):
            st[j] = 0

线性筛法:本质上一个合数只会被最小质因子筛掉,减少了埃氏筛法的重复计算

n = 100 
st = [0] * (n + 1) 
primes = []  

for i in range(2, n + 1):
    if not st[i]:
        primes.append(i)  
    j = 0 
    while j < len(primes) and primes[j] <= n / i:
        st[primes[j] * i] = 1  
        if i % primes[j] == 0: 
            break
        j += 1

print(primes) 
约数
  • 分解质因数(试除法)
res = []
for i in range(1, int(n/i)+1):
	if n % i == 0:
    	res.append(i)
    	if (i != n / i) res.append(n / i)
  • 约数其他求解

    原理:每个数都能够质因数分解,可写为:
    n = p 1 a 1 × p 2 a 2 × p 3 a 3 × p 4 a 4 . . . n = p_1^{a_1} \times p_2^{a_2} \times p_3^{a_3} \times p_4^{a_4}... n=p1a1×p2a2×p3a3×p4a4...
    其中, p 1 , p 2 . . . p_1,p_2... p1,p2...表示质因数, a 1 , a 2 . . . a_1,a_2... a1,a2...表示质因数的个数。

    以360为例,可以分解为2 * 2 * 2 * 3 * 3 * 5,可以写为 360 = 2 3 × 3 2 × 5 360 = 2^3 \times 3 ^2 \times 5 360=23×32×5

    其中, p 1 a 1 p_1^{a_1} p1a1的约数个数有 a 1 + 1 a_1 + 1 a1+1个: p 1 0 p_1^{0} p10 p 1 1 p_1^{1} p11 p 1 2 , . . . , p_1^{2},..., p12,..., p 1 a 1 p_1^{a_1} p1a1 p 2 a 2 p_2^{a_2} p2a2 a 2 + 1 a_2+1 a2+1个,因此

    约数个数为:

    以360为例,$2^3 $的约数有: 2 1 , 2 2 , 2 3 2^1 ,2^2 ,2^3 21,22,23,有 3 3 3个,而$2^3 $和$3^2 的约数又可以组成一个新的约数,例如 6 ( 2 的约数又可以组成一个新的约数,例如 6(2 的约数又可以组成一个新的约数,例如62\times$3 ),因此,在约数相乘时还需要+1,表示当前的约数不使用,例如约数是2时,3和5就需要是0次幂,因此$2^3 $的个数为 3+1,总个数可以写为:

    n u m = ( a 1 + 1 ) ( a 2 + 1 ) ( a 3 + 1 ) ( a 4 + 1 ) . . . num =(a_1 + 1)(a_2 + 1) (a_3 + 1) (a_4 + 1) ... num=(a1+1)(a2+1)(a3+1)(a4+1)...

    约数总和为:

s u m = ( p 1 0 + p 1 1 + p 1 2 + . . . ) ( p 2 0 + p 2 1 + p 2 2 + . . . ) . . . ( p k 0 + p k 1 + p k 2 + . . . ) sum =(p_1^{0}+p_1^{1}+p_1^{2}+...)(p_2^{0}+p_2^{1}+p_2^{2}+...) ...(p_k^{0}+p_k^{1}+p_k^{2}+...) sum=(p10+p11+p12+...)(p20+p21+p22+...)...(pk0+pk1+pk2+...)

def divide(x):
    primes = {}
    for i in range(2, int(x/i) + 1):
        if(x % i == 0):
            s = 0
            while (x % i == 0):
            	x //= i
                s += 1
        	primes[i] = s
    return primes
 
n = 360
primes = divide(n)
primes_count = 1
primes_sum = 1 
for prime, cnt in primes.items:
    primes_count *=  (cnt + 1)
    primes_sum_tmp = 0
    for i in range(cnt + 1):
        primes_sum_tmp += (prime ** i)
    primes_sum *= primes_sum_tmp
print(f"约数的个数为:{primes_count}")
print(f"约数的总数为:{primes_sum}")
  • 欧几里得算法(最大公约数)

核心思想:a, b 的最大公约数就是 b, a mod b 的最大公约数

def gcd(x, y):
    if y == 0:return x
	else: return gcd(y, x % y)

你可能感兴趣的:(算法,python,算法,数论,质数,约数)