【算法】欧拉函数、快速幂、容斥原理
欧拉函数
内容:表示1-n中与n互质的个数
原理:一个数可以被质因子表示,而除了质因子及其倍数,剩下的个数都是与n互质
推导(容斥原理):
1-N总共有N个数,首先将质因子
p
1
,
p
2
.
.
.
p
n
p_1,p_2...p_n
p1,p2...pn中的倍数减去,因为质因子的倍数与n是不互质的,因此首先减去质因子倍数的个数:
N
=
N
−
N
p
1
−
N
p
2
−
N
p
3
N = N- \frac{N}{p_1}- \frac{N}{p_2}- \frac{N}{p_3}
N=N−p1N−p2N−p3N
又因为质因子
p
1
,
p_1,
p1,
p
2
p_2
p2可能有公共的倍数数字,在这个过程可能被减掉两次(例如6是2,3的倍数,在上述过程中6会被减掉两次),因此还需要再加上一次,所以有:
N
=
N
+
N
p
1
p
2
+
N
p
2
p
3
N = N+ \frac{N}{p_1p_2}+ \frac{N}{p_2p_3}
N=N+p1p2N+p2p3N
以此类推,利用容斥原理的思想,可得:
φ
(
N
)
=
N
(
1
−
1
p
1
)
(
1
−
1
p
2
)
.
.
.
(
1
−
1
p
k
)
\varphi(N)=N(1-\frac{1}{p_1})(1-\frac{1}{p_2})...(1-\frac{1}{p_k})
φ(N)=N(1−p11)(1−p21)...(1−pk1)
def ola(x):
res = x
for i in range(2, int(x/i) + 1):
if(x % i == 0):
while (x % i == 0):
x //= i
res *= ((i-1)/i)
if (x > 1) res*= ((x-1)/x)
- 筛法求欧拉函数
快速幂
内容:快速求出 a k m o d p a^k\ mod \ p ak mod p的结果,一般做法的时间复杂度是 O ( k ) O(k) O(k),快速幂的时间复杂度是 O ( l o g k ) O(logk) O(logk)
思路:将k分解成2的指数幂相加,例如 2 5 2^5 25的5可以转换为2进制形式101,因此 2 5 2^5 25可以写为 2 2 0 × 2 2 2 2^{2^0}\times2^{2^2} 220×222,最多只需要进行 l o g k logk logk次操作
应用:快速幂求逆元
def qmi(x, k, p):
res = 1
while k:
if (k & 1) res *= (a % p)
k >>= 1
a = a * a % p
return res
- 求逆元
要求:已知b,求使得 b a m o d p = 1 \frac{b}{a} \ mod \ p=1 ab mod p=1成立的a值
[!note]
费马小定理:
如果 p 是素数,且 a 是整数,并且 a 不被 p 整除,那么:
a p − 1 ≡ 1 ( m o d p ) a^ {p−1}≡1 (mod\ p) ap−1≡1(mod p)
注:如果能够整除的话是不可能会mod == 1的
所以
b
a
m
o
d
p
=
1
\frac{b}{a} \ mod \ p=1
ab mod p=1可以写为
b
⋅
x
m
o
d
p
=
1
b ·x \ mod \ p=1
b⋅x mod p=1,利用费马小定理有:
b
⋅
b
p
−
2
≡
1
(
m
o
d
p
)
b · b^{p-2}≡1 (mod\ p)
b⋅bp−2≡1(mod p)
即
a
=
b
p
−
2
a = b^{p-2}
a=bp−2,最后只需利用快速幂求出
b
p
−
2
b^{p-2}
bp−2
容斥原理
- 能被整除的数
要求:求出1-n中可以被 p 1 , p_1, p1, p 2 , p_2, p2, p 3 . . . p_3... p3...等质数至少一个整除的整数有多少个
# 求1-360中有多少个可以整除2,3,5的数字个数
p = [2, 3, 5]
n = 360
k = len(p) #表示一个有多少种集合个数,可以被2整除的为一个集合,可以被3整除的为一个集合...
for i in range(1 << k): # 二进制优化,i表示选择哪些集合,100(4)表示只有选择可以被2整除的集合,101(5)表示选择可以被2和5整除的集合
for j in range(k):
cnt = 0
t = 1
if (i >> j & 1): # 表示选取第k-j个集合
cnt += 1
if t * p[j] > n: # 说明目前所选择的集合在1-n的情况下不可能有交集,例如1-20中,不可能存在同时可以除以2 3 5的数字,最小的数字为2*3*5
t = -1
break
t *= p[j]
if t != -1:
if cnt % 2 != 0:
res += n / t # 奇数集合的交集要增
else:
res -= n / t # 偶数集合的交集要减
原文地址:https://blog.csdn.net/weixin_51908696/article/details/144073825
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!