前言
长文警告
这是暑假的一个课件,突然想起来,就发出来了。
全部有关的习题的题单:https://www.luogu.com.cn/training/184246
由于 BSGS 和 拉格朗日插值 是后面临时加的,所以顺序被调到了前面,而且没有习题。
以下为原文(略有改变)
数论基础
————————by jiangtaizhe001 ————————by jiangtaizhe001
首先默认讨论的数全是整数。
整除、取余、同余的定义
记 a = b q + r a = b q + r ,其中 q ≠ 0 , 0 ≤ r < q q ≠ 0 , 0 ≤ r < q ,则称 a mod q = r a mod q = r 。
如果 r = 0 r = 0 即 a mod b = 0 a mod b = 0 那么称 q q 整除 a a ,记作 q ∣ a q ∣ a ,此时 q q 为 a a 的约数,a a 是 q q 的倍数。
如果 r ≠ 0 r ≠ 0 即 a mod p ≠ 0 a mod p ≠ 0 ,那么称 q q 不整除 a a ,记作 q ∤ a q ∤ a 。
如果 a mod p = b mod p a mod p = b mod p ,那么称 a , b a , b 模 p p 同余,记作 a ≡ b ( mod p ) a ≡ b ( mod p )
整除、同余的性质
a ∣ b ⇒ | a | ≤ | b | a ∣ b ⇒ k a ∣ k b a ∣ b , b ∣ c ⇒ a ∣ c a ∣ b ⇒ | a | ≤ | b | a ∣ b ⇒ k a ∣ k b a ∣ b , b ∣ c ⇒ a ∣ c
a ≡ b ( mod p ) ⇒ p ∣ ( a − b ) a ≡ b ( mod p ) ⇒ p ∣ ( a − b )
a ≡ b ( mod p ) ⇒ a + c ≡ b + c ( mod p ) a ≡ b ( mod p ) ⇒ a + c ≡ b + c ( mod p )
a ≡ b ( mod p ) ⇒ a c ≡ b c ( mod p ) a ≡ b ( mod p ) ⇒ a c ≡ b c ( mod p )
a ≡ b ( mod p ) ⇒ a n ≡ b n ( mod p ) a ≡ b ( mod p ) ⇒ a n ≡ b n ( mod p )
质数与合数
将全体正整数按照约数个数分类可以分为质数(又称素数)、合数和 1 1 。
质数有 2 2 个约数,合数的约数数量 ≥ 2 ≥ 2 ,1 1 只有一个约数,1 1 既不是质数也不是合数。
质数的数量是无限的。
证明:
假设质数数量有限,那么设有 n n 个质数,分别为 p 1 , p 2 , … , p n p 1 , p 2 , … , p n 。
考虑 t = ( n ∏ i = 1 p i ) + 1 t = ( ∏ i = 1 n p i ) + 1 。
如果这个数字是质数,那么显然 t > p i t > p i ,假设不成立。
如果这个数字不是质数,我们发现 p i p i 都不是 t t 的约数,假设不成立。
所以推出原假设矛盾,故质数有无数个。
我们一般用 π ( n ) π ( n ) 代表小于等于 n n 的质数个数。
当 n n 比较大的时候我们可以认为 π ( n ) ∼ x ln x π ( n ) ∼ x ln x 。
筛法
一个一个判断(筛至根号):O ( n √ n ) O ( n n )
埃拉托斯特尼筛法:O ( n log log n ) O ( n log log n )
欧拉筛(线性筛):O ( n ) O ( n )
当然埃氏筛可以使用 bitset
进行优化,欧拉筛还可以筛大部分积性函数。
欧拉函数
定义
φ ( n ) φ ( n ) 代表 小于等于 n n 并且与 n n 互质的正整数数的个数。
计算
将 n n 进行质因数分解得到 n = ∏ k i = 1 p a i i ( a i > 0 ) n = ∏ i = 1 k p i a i ( a i > 0 )
根据欧拉函数定义可得
φ ( n ) = n × k ∏ i = 1 ( 1 − 1 p i ) φ ( n ) = n × ∏ i = 1 k ( 1 − 1 p i )
证明略。
若 gcd ( a , b ) = 1 gcd ( a , b ) = 1 则 φ ( a ) × φ ( b ) = φ ( a × b ) φ ( a ) × φ ( b ) = φ ( a × b ) (欧拉函数是积性函数,可以用上面的结论证明)
根据以上结论可以在 O ( √ n ) O ( n ) 时间内求出 φ ( n ) φ ( n ) ,可以利用线性筛在 O ( n ) O ( n ) 的时间内求出 φ ( 1 ) , φ ( 2 ) , … , φ ( n ) φ ( 1 ) , φ ( 2 ) , … , φ ( n ) 。
欧拉定理与费马小定理
当 gcd ( a , p ) = 1 gcd ( a , p ) = 1 时,a φ ( p ) ≡ 1 ( mod p ) a φ ( p ) ≡ 1 ( mod p )
证明:
根据欧拉函数的定义,满足 1 ≤ r ≤ p 1 ≤ r ≤ p 并且 gcd ( r , p ) = 1 gcd ( r , p ) = 1 的数字 r r 的数量为 φ ( p ) φ ( p ) 个,记作 r 1 , r 2 , … , r φ ( p ) r 1 , r 2 , … , r φ ( p ) ,显然 r i r i 两两模 p p 不同余。
不难得到对于任意的 i i 有 gcd ( a r i , p ) = 1 gcd ( a r i , p ) = 1 。
假设存在 1 ≤ i < j ≤ m 1 ≤ i < j ≤ m 使得 a r i ≡ a r j ( mod p ) a r i ≡ a r j ( mod p ) 成立,由于 gcd ( a , p ) = 1 gcd ( a , p ) = 1 所以 r i ≡ r j ( mod p ) r i ≡ r j ( mod p ) ,所以假设不成立,也就是说 a r i a r i 两两模 p p 不同余。
所以说对于任意的 1 ≤ i ≤ m 1 ≤ i ≤ m ,存在且仅存在一个 j j 使得 r i ≡ a r j ( mod p ) , 1 ≤ j ≤ m r i ≡ a r j ( mod p ) , 1 ≤ j ≤ m
也就是说
φ ( m ) ∏ i = 1 r i ≡ φ ( m ) ∏ i = 1 a r i ( mod p ) ∏ i = 1 φ ( m ) r i ≡ ∏ i = 1 φ ( m ) a r i ( mod p )
由于 gcd ( r i , p ) = 1 gcd ( r i , p ) = 1 ,所以可以将相同部分的 φ ( p ) ∏ i = 1 r i ∏ i = 1 φ ( p ) r i 约去。
得到
a φ ( p ) ≡ 1 ( mod p ) a φ ( p ) ≡ 1 ( mod p )
当 p p 为质数的时候,φ ( p ) = p − 1 φ ( p ) = p − 1 ,那么就可以得到
a p − 1 ≡ 1 ( mod p ) a p − 1 ≡ 1 ( mod p )
这就是费马小定理。
gcd、exgcd
gcd
gcd ( a , b ) = gcd ( b , a mod b ) gcd ( a , b ) = gcd ( b , a mod b )
证明如下:
设 a = b q + r a = b q + r 并且 0 ≤ r < b 0 ≤ r < b ,显然 r = a mod b r = a mod b ,
设 d ∣ a d ∣ a 且 d ∣ b d ∣ b ,d d 就是 a , b a , b 的公约数,
由 a = b q + r a = b q + r 得 a d = q × b d + r d a d = q × b d + r d ,
也就是 r d = a d − q × b d r d = a d − q × b d
因为 d ∣ a , d ∣ b d ∣ a , d ∣ b ,所以 a d , q × b d a d , q × b d 都是整数,
所以 r d r d 也是整数,d d 也是 b , a mod b b , a mod b 的公约数,
同理我们也可以设 e ∣ b e ∣ b 且 e ∣ a mod b e ∣ a mod b ,
同理可以证明 e e 也是 a , b a , b 的公约数。
换句话说, a , b a , b 的公约数都是 b , a mod b b , a mod b 的公约数,b , a mod b b , a mod b 的公约数也都是 a , b a , b 的公约数,
也就是说 a , b a , b 和 b , a mod b b , a mod b 的公约数都相同,那么它们的最大公约数也都相等,也就是 gcd ( a , b ) = gcd ( b , a mod b ) gcd ( a , b ) = gcd ( b , a mod b )
根据这个结论我们可以递归在 O ( log n ) O ( log n ) 的时间内求出两个数字的最大公约数,当两个数字为斐波那切数列的相邻两项的时候为最坏情况。这个算法被称为欧几里得辗转相除法。
裴蜀定理
裴蜀定理(又称贝祖定理):
如果gcd ( a , b ) ∣ c gcd ( a , b ) ∣ c ,那么关于 x , y x , y 的一元二次方程 a x + b y = c a x + b y = c 有解。
可以根据 exgcd 辗转相除然后回带的过程来证明,这里就略去证明。
exgcd
找到关于 x , y x , y 的一元二次方程 a x + b y = gcd ( a , b ) a x + b y = gcd ( a , b ) 的一组解
根据 gcd 的过程,将原方程转化为
b x ′ + ( a mod b ) y ′ = gcd ( b , a mod b ) b x ′ + ( a mod b ) y ′ = gcd ( b , a mod b )
因为 gcd ( a , b ) = gcd ( b , a mod b ) gcd ( a , b ) = gcd ( b , a mod b ) ,所以联立上面两式可得
a x + b y = b x ′ + ( a mod b ) y ′ a x + b y = b x ′ + ( a mod b ) y ′
根据 a mod b = a − ⌊ a b ⌋ × b a mod b = a − ⌊ a b ⌋ × b 带入化简可得
( x − y ′ ) a + ( y − x ′ + ⌊ a b ⌋ × y ′ ) b = 0 ( x − y ′ ) a + ( y − x ′ + ⌊ a b ⌋ × y ′ ) b = 0
此时我们可以得到
{ x = y ′ y = x ′ − ⌊ a b ⌋ × y ′ { x = y ′ y = x ′ − ⌊ a b ⌋ × y ′
这样可以递归求解,递归边界就是 b = 0 b = 0 ,返回 ( x , y ) = ( 1 , 0 ) ( x , y ) = ( 1 , 0 ) 即可。
当我们有一组解 x = x ′ , y = y ′ x = x ′ , y = y ′ 的时候,就可以得出通解:
⎧ ⎪
⎪
⎪ ⎨ ⎪
⎪
⎪ ⎩ x = x ′ + k b gcd ( a , b ) y = y ′ − k a gcd ( a , b ) { x = x ′ + k b gcd ( a , b ) y = y ′ − k a gcd ( a , b )
其中 k k 为任意整数。
更一般的,对于任意的一个关于 x , y x , y 的二元一次方程 a x + b y = c a x + b y = c
如果 gcd ( a , b ) ∣ c gcd ( a , b ) ∣ c 那么我们先解出方程 a x + b y = gcd ( a , b ) a x + b y = gcd ( a , b ) 的一组特解 x ′ , y ′ x ′ , y ′ ,设 m = c gcd ( a , b ) m = c gcd ( a , b ) ,不难得出通解:
⎧ ⎪
⎪
⎪ ⎨ ⎪
⎪
⎪ ⎩ x = m × x ′ + k b gcd ( a , b ) y = m × y ′ − k a gcd ( a , b ) { x = m × x ′ + k b gcd ( a , b ) y = m × y ′ − k a gcd ( a , b )
应用:解线性同余方程
考虑关于 x x 的以下方程:
a x ≡ b ( mod p ) a x ≡ b ( mod p )
根据同余的定义可得
存在一个正整数 k k 满足
a x = k p + b a x = k p + b
也就是
a x − p k = b a x − p k = b
这就是一个关于 x , k x , k 的一个一元二次方程了,直接使用 exgcd 即可。
乘法逆元
定义
对于整数 x x ,如果 gcd ( a , p ) = 1 gcd ( a , p ) = 1 ,那么不难证明存在一个 0 ≤ a < p 0 ≤ a < p 使得 a x ≡ 1 ( mod p ) a x ≡ 1 ( mod p ) ,那么称 a a 在模 p p 下的逆元为 x x ,记作 1 a 1 a 或 a − 1 a − 1 。
计算
方法一:快速幂
当 p p 为质数的时候,可得
a p − 1 ≡ 1 ( mod p ) a p − 1 ≡ 1 ( mod p )
所以
a − 1 ≡ a p − 2 ( mod p ) a − 1 ≡ a p − 2 ( mod p )
方法二:exgcd
其实就是解这个线性同余方程即可。
方法三:线性逆元线性求
考虑在 O ( n ) O ( n ) 的时间内求出 1 , 2 , … , n 1 , 2 , … , n 所有数字模 p p 的逆元。(下面的逆元默认为模 p p 意义下)
显然 1 1 的逆元为 1 1 ,然后假设我们已经求出 1 , 2 , 3 , … , a − 1 1 , 2 , 3 , … , a − 1 的逆元,现在求 a a 的逆元。
设 p = a q + r p = a q + r 其中 0 ≤ r < a 0 ≤ r < a ,显然 q = ⌊ p a ⌋ , r = p mod a q = ⌊ p a ⌋ , r = p mod a
显然
a q + r ≡ 0 ( mod p ) a q + r ≡ 0 ( mod p )
移项得
a q ≡ − r ( mod p ) a q ≡ − r ( mod p )
两边同时乘上 a − 1 r − 1 a − 1 r − 1 ,得
a − 1 ≡ q × r − 1 ( mod p ) a − 1 ≡ q × r − 1 ( mod p )
也就是
a − 1 ≡ − ⌊ p a ⌋ × ( p mod a ) ( mod p ) a − 1 ≡ − ⌊ p a ⌋ × ( p mod a ) ( mod p )
这样就可以 O ( n ) O ( n ) 求了。
方法四:阶乘逆元线性求
在做组合题的时候,根据公式 C m n = n ! m ! × ( n − m ) ! C n m = n ! m ! × ( n − m ) ! ,我们发现只需要预处理出 n ! n ! 和 n ! − 1 n ! − 1 就可以 O ( 1 ) O ( 1 ) 求组合数在模一个大质数的结果了。
其实不难发现
( n + 1 ) ! − 1 × ( n + 1 ) ≡ n ! − 1 ( mod p ) ( n + 1 ) ! − 1 × ( n + 1 ) ≡ n ! − 1 ( mod p )
所以只需要反着刷一遍就好,时间复杂度是 O ( n ) O ( n ) 。
中国剩余定理
中国剩余定理 (Chinese Remainder Theorem) 简称CRT。
CRT
考虑解以下关于 x x 的方程:
⎧ ⎪
⎪
⎪
⎪
⎪
⎪
⎪ ⎨ ⎪
⎪
⎪
⎪
⎪
⎪
⎪ ⎩ x ≡ a 1 ( mod m 1 ) x ≡ a 2 ( mod m 2 ) x ≡ a 3 ( mod m 3 ) ⋮ x ≡ a n ( mod m n ) { x ≡ a 1 ( mod m 1 ) x ≡ a 2 ( mod m 2 ) x ≡ a 3 ( mod m 3 ) ⋮ x ≡ a n ( mod m n )
保证 m i m i 两两互质。
我们考虑如何解这个方程。
我们考虑对于每个 i i 找到一个 c i c i ,使得
c i ≡ 1 ( mod m i ) ( 1 ) c i ≡ 0 ( mod m j ) ( i ≠ j ) ( 2 ) c i ≡ 1 ( mod m i ) ( 1 ) c i ≡ 0 ( mod m j ) ( i ≠ j ) ( 2 )
这样显然解就是
x ≡ n ∑ i = 1 a i c i ( mod n ∏ i = 1 m i ) x ≡ ∑ i = 1 n a i c i ( mod ∏ i = 1 n m i )
考虑如何得到 c i c i ,显然 c i c i 一定是 M i = n ∏ j = 1 , j ≠ i m j M i = ∏ j = 1 , j ≠ i n m j 的倍数。
这样就已经满足 ( 2 ) ( 2 ) 式了,接下来考虑如何满足 ( 1 ) ( 1 ) 式。
注意到求出 M i M i 在模 m i m i 意义下的逆元 M − 1 i M i − 1 ,令 c i = M i × M − 1 i c i = M i × M i − 1 就可以了。由于满足 m i m i 两两互质,所以逆元肯定存在。
总结中国剩余定理的步骤:
计算 M = n ∏ i = 1 m i M = ∏ i = 1 n m i
对于所有的 1 ≤ i ≤ n 1 ≤ i ≤ n 计算 M i = M m i M i = M m i
令 M − 1 i M i − 1 为 M i M i 在模 m i m i 意义下的逆元
方程的解为
x ≡ n ∑ i = 1 a i M i M − 1 i ( mod M ) x ≡ ∑ i = 1 n a i M i M i − 1 ( mod M )
证明略。
exCRT
更一般的,如果不保证 m i m i 两两互质,是否能够以上方法得到通解呢?
这是我们发现这个 c i c i 不一定能够找到,因为 M i M i 在模 m i m i 意义下的逆元不一定存在。
所以我们需要寻找另外的解法。
我们简化一下问题,我们可以先考虑两个方程的情况,然后两两合并方程即可。
{ x ≡ a 1 ( mod m 1 ) x ≡ a 2 ( mod m 2 ) { x ≡ a 1 ( mod m 1 ) x ≡ a 2 ( mod m 2 )
根据前面的做法,我们可以把同余方程转化为一元二次不定方程,得到
{ x = m 1 q + a 1 x = m 2 p + a 2 { x = m 1 q + a 1 x = m 2 p + a 2
两式相减可得
m 1 q − m 2 p = a 2 − a 1 m 1 q − m 2 p = a 2 − a 1
利用 exgcd 解出这个关于 p , q p , q 的方程,如果无解就说明原方程无解。
这样就可以解出方程,解为
x ≡ a 1 q + b 1 ( mod lcm ( m 1 , m 2 ) ) x ≡ a 1 q + b 1 ( mod lcm ( m 1 , m 2 ) )
或者是
x ≡ a 2 p + b 2 ( mod lcm ( m 1 , m 2 ) ) x ≡ a 2 p + b 2 ( mod lcm ( m 1 , m 2 ) )
这样复杂度也是 O ( n log m i ) O ( n log m i ) 的,但是稍微会难写一点。
整除分块
整除分块又叫数论分块。
引-UVA11526 H(n)
求出
n ∑ i = 1 ⌊ n i ⌋ ∑ i = 1 n ⌊ n i ⌋
多组数据,0 ≤ n ≤ 2 31 − 1 0 ≤ n ≤ 2 31 − 1 ,数据组数 T ≤ 1000 T ≤ 1000 。
显然直接枚举是不行的。我们可以令 f ( x ) = ⌊ n i ⌋ f ( x ) = ⌊ n i ⌋ ,先令 n = 10 n = 10 ,作出函数 y = f ( x ) y = f ( x ) 的图像。
我们发现,虽然自变量 x x 的取值有 10 10 种,但是 f ( x ) f ( x ) 的取值只有 5 5 种。并且当 n = 100 n = 100 的时候,x x 的取值又 100 100 种,但是 f ( x ) f ( x ) 的取值只有 19 19 种。
不难发现以下结论:
∀ n ∈ N + , ∣ ∣ { ⌊ n i ⌋ ∣ i ∈ N + , i ≤ n } ∣ ∣ ≤ 2 ⌊ √ n ⌋ ∀ n ∈ N + , | { ⌊ n i ⌋ ∣ i ∈ N + , i ≤ n } | ≤ 2 ⌊ n ⌋
证明:
当 i ≤ ⌊ √ n ⌋ i ≤ ⌊ n ⌋ 时,⌊ n i ⌋ ⌊ n i ⌋ 最多 ⌊ √ n ⌋ ⌊ n ⌋ 个数字。
当 ⌊ √ n ⌋ < i ≤ n ⌊ n ⌋ < i ≤ n 时,1 ≤ ⌊ n i ⌋ ≤ ⌊ √ n ⌋ 1 ≤ ⌊ n i ⌋ ≤ ⌊ n ⌋ ,最多有 ⌊ √ n ⌋ ⌊ n ⌋ 个数字。
因此最多只有 2 ⌊ √ n ⌋ 2 ⌊ n ⌋ 个数字。
所以说,我们可以能够预处理出每个使 f ( x ) f ( x ) 相同的区间来更快地计算答案,这样的时间复杂度是 O ( √ n ) O ( n ) 的,提高了不少。
结论
对于一个数字 n n ,如果 ⌊ n i ⌋ = ⌊ n j ⌋ ⌊ n i ⌋ = ⌊ n j ⌋ 成立,那么满足 i < j ≤ n i < j ≤ n 最大的 j j 为 ⎢ ⎢
⎢
⎢
⎢ ⎣ n ⌊ n i ⌋ ⎥ ⎥
⎥
⎥
⎥ ⎦ ⌊ n ⌊ n i ⌋ ⌋
结论证明
引理
引理:
∀ a , b , c ∈ Z , a b c ≠ 0 , ⌊ a b c ⌋ = ⎢ ⎢
⎢
⎢
⎢ ⎣ ⌊ a b ⌋ c ⎥ ⎥
⎥
⎥
⎥ ⎦ ∀ a , b , c ∈ Z , a b c ≠ 0 , ⌊ a b c ⌋ = ⌊ ⌊ a b ⌋ c ⌋
证明:
设
a b = ⌊ a b ⌋ + r , 0 ≤ r < 1 a b = ⌊ a b ⌋ + r , 0 ≤ r < 1
那么
⌊ a b c ⌋ = ⌊ ( ⌊ a b ⌋ + r ) × 1 c ⌋ = ⎢ ⎢
⎢
⎢
⎢ ⎣ ⌊ a b ⌋ c + r c ⎥ ⎥
⎥
⎥
⎥ ⎦ = ⎢ ⎢
⎢
⎢
⎢ ⎣ ⌊ a b ⌋ c ⎥ ⎥
⎥
⎥
⎥ ⎦ ⌊ a b c ⌋ = ⌊ ( ⌊ a b ⌋ + r ) × 1 c ⌋ = ⌊ ⌊ a b ⌋ c + r c ⌋ = ⌊ ⌊ a b ⌋ c ⌋
结论证明
首先显然有
⌊ n i ⌋ ≤ n i ⌊ n i ⌋ ≤ n i
所以
⎢ ⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢ ⎣ n ⌊ n ⌊ n i ⌋ ⌋ ⎥ ⎥
⎥
⎥
⎥
⎥
⎥
⎥
⎥ ⎦ ≥ ⎢ ⎢
⎢
⎢
⎢
⎢
⎢
⎢
⎢ ⎣ n ⌊ n n i ⌋ ⎥ ⎥
⎥
⎥
⎥
⎥
⎥
⎥
⎥ ⎦ ≥ ⌊ n ⌊ i ⌋ ⌋ = ⌊ n i ⌋ ⌊ n ⌊ n ⌊ n i ⌋ ⌋ ⌋ ≥ ⌊ n ⌊ n n i ⌋ ⌋ ≥ ⌊ n ⌊ i ⌋ ⌋ = ⌊ n i ⌋
所以说最大的 j j 满足 ⌊ n i ⌋ = ⌊ n j ⌋ ⌊ n i ⌋ = ⌊ n j ⌋ 为 ⎢ ⎢
⎢
⎢
⎢ ⎣ n ⌊ n i ⌋ ⎥ ⎥
⎥
⎥
⎥ ⎦ ⌊ n ⌊ n i ⌋ ⌋ 。
实例
假设我们需要计算式子大概为类似 n ∑ i = 1 f ( i ) ⌊ n i ⌋ ∑ i = 1 n f ( i ) ⌊ n i ⌋ 的形式并且可以得到 f ( i ) f ( i ) 的前缀和 s ( i ) s ( i ) ,那么我们可以在 O ( √ n ) O ( n ) 的时间内求出这个式子。(假设 s ( i ) s ( i ) 调用复杂度为 O ( 1 ) O ( 1 ) )
代码大致如下:
int l=1 ,r,sum=0 ;
while (l<=n){
r=n/(n/l);
sum+=n/l*(s (r)-s (l-1 ));
l=r+1 ;
}
多维数论分块
有些时候式子可能会更加复杂,大概是类似于 n ∑ i = 1 f ( i ) m ∏ j = 1 ⌊ a j i ⌋ ∑ i = 1 n f ( i ) ∏ j = 1 m ⌊ a j i ⌋ ,此时 i i 所在的右端点就会变成 m min j = 1 ⎢ ⎢
⎢
⎢
⎢ ⎣ n j ⌊ n j i ⌋ ⎥ ⎥
⎥
⎥
⎥ ⎦ min j = 1 m ⌊ n j ⌊ n j i ⌋ ⌋ 。当然其实 n = 2 n = 2 的情况最常见。
应用
数论分块更多结合莫比乌斯反演来降低时间复杂度。
卢卡斯定理
卢卡斯定理用于求出当模数为一个比较小的质数的时候 ( n m ) ( n m ) 的值。
这里就给个公式吧,其实是因为我大不会证明。
( n m ) ≡ ( ⌊ n / p ⌋ ⌊ m / p ⌋ ) × ( n mod p m mod p ) ( mod p ) ( n m ) ≡ ( ⌊ n / p ⌋ ⌊ m / p ⌋ ) × ( n mod p m mod p ) ( mod p )
其中 p p 为质数。
这时我们只需要预处理出 1 ! , 2 ! , … , ( p − 1 ) ! 1 ! , 2 ! , … , ( p − 1 ) ! 这些数字模 p p 的值以及模 p p 意义下的逆元就可以通过递归求出任意的 ( n m ) ( n m ) 了。空间复杂度 O ( p ) O ( p ) ,时间复杂度为 O ( p + log p n ) O ( p + log p n ) 。
当 p p 不为质数的时候就需要用扩展卢卡斯定理来求了,这里不写出。
BSGS
基础篇
找到方程
a x ≡ b ( mod p ) a x ≡ b ( mod p )
的最小整数解,其中 gcd ( a , p ) = 1 gcd ( a , p ) = 1 ,1 ≤ a , p ≤ 10 12 1 ≤ a , p ≤ 10 12 。
首先根据欧拉定理,我们知道
a x ≡ a x mod φ ( p ) ( mod p ) a x ≡ a x mod φ ( p ) ( mod p )
由于 φ ( p ) < p φ ( p ) < p ,所以如果方程有解,那么在 [ 0 , p ] [ 0 , p ] 内肯定会有解。
直接枚举显然是不行的,我们发现因为 gcd ( a , p ) = 1 gcd ( a , p ) = 1 ,所以 a a 的任意次方在模 p p 意义下都存在逆元,我们是否能够使用这一个性质来解这个方程呢?
令 x = A ⌈ √ p ⌉ + B x = A ⌈ p ⌉ + B
这样就有
a A ⌈ √ p ⌉ + B ≡ b ( mod p ) a A ⌈ p ⌉ + B ≡ b ( mod p )
这样不难得到
a A ⌈ √ p ⌉ ≡ a − B b ( mod p ) a A ⌈ p ⌉ ≡ a − B b ( mod p )
我们可以对于所有的 0 ≤ B ≤ ⌈ √ p ⌉ 0 ≤ B ≤ ⌈ p ⌉ 求出 a − B b a − B b 在模 p p 下的值,放到一个哈希表里面,然后枚举 A A 检验就可以了。
时间复杂度 O ( √ p ) O ( p )
扩展篇
如果 gcd ( a , p ) ≠ 1 gcd ( a , p ) ≠ 1 ,我们应该怎么办呢?
我们发现这时我们对于所有的 0 ≤ B ≤ ⌈ √ p ⌉ 0 ≤ B ≤ ⌈ p ⌉ ,我们不一定可以找到 a B a B 在模 p p 意义下的逆元,所以我们试图通过一些方法来转化。
众所周知,a c ≡ b c ( mod p c ) ⇒ a ≡ b ( mod p ) a c ≡ b c ( mod p c ) ⇒ a ≡ b ( mod p )
我们可以利用这个性质来转化原式。
令 t 1 = gcd ( a , p ) t 1 = gcd ( a , p )
这样我们就得到
a t 1 × a x − 1 ≡ b t 1 ( mod p t 1 ) a t 1 × a x − 1 ≡ b t 1 ( mod p t 1 )
继续令 t 2 = gcd ( a , p t 1 ) t 2 = gcd ( a , p t 1 ) ,得到
a 2 t 1 t 2 × a x − 2 ≡ b t 1 t 2 ( mod p t 1 t 2 ) a 2 t 1 t 2 × a x − 2 ≡ b t 1 t 2 ( mod p t 1 t 2 )
接下来令 t 3 = gcd ( a , p t 1 t 2 ) t 3 = gcd ( a , p t 1 t 2 ) ,得到
a 3 t 1 t 2 t 3 × a x − 3 ≡ b t 1 t 2 t 3 ( mod p t 1 t 2 t 3 ) a 3 t 1 t 2 t 3 × a x − 3 ≡ b t 1 t 2 t 3 ( mod p t 1 t 2 t 3 )
我们可以继续进行这样的操作若干次,直到 gcd ( a , p ∏ n i = 1 t i ) = 1 gcd ( a , p ∏ i = 1 n t i ) = 1 ,得到
a n ∏ n i = 1 t i × a x − n ≡ b ∏ n i = 1 t i ( mod p ∏ n i = 1 t i ) a n ∏ i = 1 n t i × a x − n ≡ b ∏ i = 1 n t i ( mod p ∏ i = 1 n t i )
这样就可以转化为 BSGS 求解了。
不过要注意两个细节:
解可能小于 n n ,所以需要是否存在小于 n n 的解。
如果 ∏ n i = 1 t i ∤ b ∏ i = 1 n t i ∤ b 那么无解。
显然 n n 是 O ( log p ) O ( log p ) 级别,所以时间复杂度还是 O ( √ p ) O ( p )
拉格朗日插值
给定一个 n − 1 n − 1 次函数 f ( x ) f ( x ) ,已知
⎧ ⎪
⎪
⎪
⎪ ⎨ ⎪
⎪
⎪
⎪ ⎩ f ( x 1 ) = y 1 f ( x 2 ) = y 2 ⋮ f ( x n ) = y n { f ( x 1 ) = y 1 f ( x 2 ) = y 2 ⋮ f ( x n ) = y n
现在求出 f ( k ) f ( k ) ,k k 为任意值。
显然我们可以通过差分、高斯消元来求出 f ( x ) f ( x ) 的表达式,进一步求出 f ( k ) f ( k ) ,但是这样的复杂度都是 O ( n 3 ) O ( n 3 ) 的,能否找到更优的解法呢?
我们可以试试能不能 直接构造 出 f ( x ) f ( x ) 的表达式。
考虑先构造 n n 个函数 f 1 ( x ) , f 2 ( x ) , … , f n ( x ) f 1 ( x ) , f 2 ( x ) , … , f n ( x ) ,使得
{ f i ( x i ) = y i f i ( x j ) = 0 ( i ≠ j ) { f i ( x i ) = y i f i ( x j ) = 0 ( i ≠ j )
显然这样就能得到 f ( x ) = ∑ n i = 1 f i ( x ) f ( x ) = ∑ i = 1 n f i ( x ) 。
考虑如何构造 f i ( x ) f i ( x )
显然 f i ( x ) f i ( x ) 存在因子
n ∏ j = 1 , j ≠ i ( x − x j ) ∏ j = 1 , j ≠ i n ( x − x j )
这样就可以设
f i ( x ) = a n ∏ j = 1 , j ≠ i ( x − x j ) f i ( x ) = a ∏ j = 1 , j ≠ i n ( x − x j )
带入点 ( x i , y i ) ( x i , y i ) 就可以得到
f i ( x ) = y i n ∏ j = 1 , j ≠ i x − x j x i − x j f i ( x ) = y i ∏ j = 1 , j ≠ i n x − x j x i − x j
所以
f ( x ) = n ∑ i = 1 y i n ∏ j = 1 , j ≠ i x − x j x i − x j f ( x ) = ∑ i = 1 n y i ∏ j = 1 , j ≠ i n x − x j x i − x j
这样虽然求 f ( x ) f ( x ) 表达式仍然是 O ( n 3 ) O ( n 3 ) ,但是如果直接单点求值的话就是 O ( n 2 ) O ( n 2 ) 的了。
习题选讲
P7960 [NOIP2021] 报数
两个人玩报数游戏,如果一个数字存在一个约数在十进制下有数字 7 7 ,那么这个数字不能被报出。上一个人报出的数字为 x x ,现在求下一个报出的数字为多少,如果上一个人报出的数字不合法输出 − 1 − 1 。
多组数据,数据组数 T ≤ 2 × 10 5 , 1 ≤ x ≤ 10 7 T ≤ 2 × 10 5 , 1 ≤ x ≤ 10 7 。
Solution
x ≤ 10 7 x ≤ 10 7 ,所以其实不需要使用线性筛,根据前面游戏的规则发现埃氏筛更加使用,所以直接用埃氏筛筛出所有能被报出的数字即可,注意不要筛到 10 7 10 7 就停。时间复杂度 O ( n log log n + T ) O ( n log log n + T ) 。(其实会小一点)
P2158 [SDOI2008] 仪仗队
有一个 N × N N × N 的方阵,现在你在方阵的左下角。如果方阵排整齐,求你能看到几个同学。N ≤ 4 × 10 4 N ≤ 4 × 10 4 。
Solution
我会莫比乌斯反演!
不难发现答案就是 N − 1 ∑ i = 0 N − 1 ∑ j = 0 [ gcd ( i , j ) = 1 ] ∑ i = 0 N − 1 ∑ j = 0 N − 1 [ gcd ( i , j ) = 1 ] 。
考虑以下内容帮助我们解题:
gcd gcd 的两个性质:gcd ( a , b ) = gcd ( b , a ) gcd ( a , b ) = gcd ( b , a ) 、gcd ( 0 , i ) = gcd ( i , 0 ) = i gcd ( 0 , i ) = gcd ( i , 0 ) = i
欧拉函数的定义:φ ( n ) = n ∑ i = 1 [ gcd ( i , n ) = 1 ] φ ( n ) = ∑ i = 1 n [ gcd ( i , n ) = 1 ]
不难得到:
N − 1 ∑ i = 0 N − 1 ∑ j = 0 [ gcd ( i , j ) = 1 ] = N − 1 ∑ i = 0 i − 1 ∑ j = 0 [ gcd ( i , j ) = 1 ] + N − 1 ∑ i = 0 N − 1 ∑ j = i + 1 [ gcd ( i , j ) = 1 ] + N − 1 ∑ i = 0 [ gcd ( i , i ) = 1 ] = 2 × N − 1 ∑ i = 0 i − 1 ∑ j = 0 [ gcd ( i , j ) = 1 ] + 1 = 2 × N − 1 ∑ i = 1 φ ( i ) + 1 ∑ i = 0 N − 1 ∑ j = 0 N − 1 [ gcd ( i , j ) = 1 ] = ∑ i = 0 N − 1 ∑ j = 0 i − 1 [ gcd ( i , j ) = 1 ] + ∑ i = 0 N − 1 ∑ j = i + 1 N − 1 [ gcd ( i , j ) = 1 ] + ∑ i = 0 N − 1 [ gcd ( i , i ) = 1 ] = 2 × ∑ i = 0 N − 1 ∑ j = 0 i − 1 [ gcd ( i , j ) = 1 ] + 1 = 2 × ∑ i = 1 N − 1 φ ( i ) + 1
跑个线性筛就可以了。时间复杂度 O ( N ) O ( N )
P2398 GCD SUM
求
n ∑ i = 1 n ∑ j = 1 gcd ( i , j ) ∑ i = 1 n ∑ j = 1 n gcd ( i , j )
其中 n ≤ 10 5 n ≤ 10 5
Solution
我会莫比乌斯反演!
n ∑ i = 1 n ∑ j = 1 gcd ( i , j ) = n ∑ d = 1 n ∑ i = 1 n ∑ j = 1 [ gcd ( i , j ) = d ] × d = n ∑ d = 1 ⌊ n / d ⌋ ∑ i = 1 ⌊ n / d ⌋ ∑ j = 1 [ gcd ( i , j ) = 1 ] × d = n ∑ d = 1 ⎛ ⎝ 2 d × ⌊ n / d ⌋ ∑ i = 1 ( φ ( i ) − 1 ) ⎞ ⎠ ( 这 步 推 导 详 见 上 一 题 ) ∑ i = 1 n ∑ j = 1 n gcd ( i , j ) = ∑ d = 1 n ∑ i = 1 n ∑ j = 1 n [ gcd ( i , j ) = d ] × d = ∑ d = 1 n ∑ i = 1 ⌊ n / d ⌋ ∑ j = 1 ⌊ n / d ⌋ [ gcd ( i , j ) = 1 ] × d = ∑ d = 1 n ( 2 d × ∑ i = 1 ⌊ n / d ⌋ ( φ ( i ) − 1 ) ) (这步推导详见上一题)
所以只需要跑个线性筛,然后预处理出 φ ( n ) φ ( n ) 的前缀和就可以了。时间复杂度 O ( n ) O ( n ) 。
P4774 [NOI2018] 屠龙勇士:
按照编号 1 → n 1 → n 顺序杀掉 n n 条巨龙,每条巨龙拥有一个初始的生命值 a i a i 。并且巨龙会在生命值为负的时候恢复生命值 p i p i ,当生命值 恰好 为 0 0 时它才会死去。
最初你拥有 m m 把攻击力已知的剑,每次可以选择一把剑来面对巨龙,当杀死巨龙后这把剑就会消失,同事玩家会获得全新的一把剑。
每次面对巨龙时,默认会选择当前拥有的,攻击力不高于巨龙初始生命值中攻击力最大的一把剑作为武器。如果没有这样的剑,则选择攻击力最低 的一把剑作为武器,设攻击力为 A T K A T K 。
每次面对每条巨龙,它都会使用上一步中选择的剑攻击巨龙固定的 x x 次,使巨龙的生命值减少 x × A T K x × A T K 。
之后,巨龙会不断恢复 p i p i 的生命值。若在使用恢复能力前或某一次恢复后其生命值为 0 0 ,则巨龙死亡,开始杀掉下一条巨龙。
现在需要求出题目中 x x 的最小值,若最小值不存在输出 − 1 − 1 。
数据范围: n ≤ 10 5 n ≤ 10 5 ,a i ≤ 10 12 a i ≤ 10 12 ,lcm ( p i ) ≤ 10 12 lcm ( p i ) ≤ 10 12 ,所有武器的攻击力 ≤ 10 6 ≤ 10 6 。
Solution
首先使用平衡树(或者是 multiset
)求出打每一只巨龙所用的剑的伤害,显然打每一只巨龙所用的剑的伤害是一个固定的值。设打第 i i 只巨龙所用的剑的伤害为 a t k i a t k i 。
然后就相当于解下面的同余方程组:
⎧ ⎪
⎪
⎪
⎪ ⎨ ⎪
⎪
⎪
⎪ ⎩ a t k 1 x ≡ a 1 ( mod p 1 ) a t k 2 x ≡ a 2 ( mod p 2 ) ⋮ a t k n x ≡ a n ( mod p n ) { a t k 1 x ≡ a 1 ( mod p 1 ) a t k 2 x ≡ a 2 ( mod p 2 ) ⋮ a t k n x ≡ a n ( mod p n )
方法一
显然每一个方程都是线性同余方程,所以可以解出这 n n 个方程,就可以直接使用 exCRT 进行求解。
方法二
还是考虑两两合并方程,然后转化为一元二次不定方程求解。
P2480 [SDOI2010]古代猪文
求出
g ∑ d ∣ n C k n mod 999911659 g ∑ d ∣ n C n k mod 999911659
其中 n , g ≤ 10 9 n , g ≤ 10 9 。
Solution
首先发现 999911659 999911659 为一个质数,所以根据欧拉定理或费马小定理可以得到所求式子就是
g ∑ d ∣ n C k n mod 9999611658 mod 999911659 g ∑ d ∣ n C n k mod 9999611658 mod 999911659
此时重点就在于求出
∑ d ∣ n C k n mod 9999611658 ∑ d ∣ n C n k mod 9999611658
枚举 k ∣ n k ∣ n 显然是 O ( √ n ) O ( n ) 的时间复杂度,但是我们发现 9999611658 9999611658 不是质数,所以通过求出阶乘及阶乘逆元在模 999611658 999611658 的值来求组合数是不可行的,因为逆元不一定存在。
但是我们考虑到 9999611658 = 2 × 3 × 4679 × 35617 9999611658 = 2 × 3 × 4679 × 35617 ,每一个质因数的次数都为 1 1 ,所以我们可以利用卢卡斯定理求出这个式子在模 2 , 3 , 4679 , 35617 2 , 3 , 4679 , 35617 下的值,然后使用 CRT 合并答案即可。
这也是 CRT 非常重要的一个用途之一。
P2261 [CQOI2007]余数求和
求出
n ∑ i = 1 k mod i ∑ i = 1 n k mod i
其中 1 ≤ n , k ≤ 10 9 1 ≤ n , k ≤ 10 9 。
n ∑ i = 1 k mod i = n ∑ i = 1 ( k − ⌊ k i ⌋ × i ) = n × k − n ∑ i = 1 ( ⌊ k i ⌋ × i ) ∑ i = 1 n k mod i = ∑ i = 1 n ( k − ⌊ k i ⌋ × i ) = n × k − ∑ i = 1 n ( ⌊ k i ⌋ × i )
直接整除分块就可以了。
注意在代码中 k/(k/i)
当 i > k i > k 的时候会因为除数为 0 0 RE 掉,需要特判。
CF 数论题目选讲
CF1458A
题目大意:
给定一个长度为 n n 的数组 a a 和一个长度为 m m 的数组 b b 。
现在对于每一个 1 ≤ j ≤ m 1 ≤ j ≤ m ,求出 gcd ( a 1 + b j , a 2 + b j , … , a n + b j ) gcd ( a 1 + b j , a 2 + b j , … , a n + b j ) 。
1 ≤ n , m ≤ 10 5 1 ≤ n , m ≤ 10 5 ,1 ≤ a i , b i ≤ 10 18 1 ≤ a i , b i ≤ 10 18
Solution
首先 n = 1 n = 1 的时候特判掉。
根据辗转相除可以知道 gcd ( a , b ) = gcd ( a , b − a ) gcd ( a , b ) = gcd ( a , b − a ) 。
所以我们可以利用这个东西把 b j b j 这一个变动的项消去,只剩下一个。
原式转化为 gcd ( a 2 − a 1 , a 3 − a 2 , … , a n − a n − 1 , a n + b j ) gcd ( a 2 − a 1 , a 3 − a 2 , … , a n − a n − 1 , a n + b j ) ,直接预处理出除掉最后一项的 gcd gcd 即可。
时间复杂度 O ( n log a i + m log b i ) O ( n log a i + m log b i )
CF1513D
题目大意:
给定一个长度为 n n 的序列 a a 和一个数字 p p 。
如果 gcd ( a i , a i + 1 , … , a j ) = min ( a i , a i + 1 , … , a j ) gcd ( a i , a i + 1 , … , a j ) = min ( a i , a i + 1 , … , a j ) ,那么就在 i , j i , j 之间连接一条边权为 min ( a i , a i + 1 , … , a j ) min ( a i , a i + 1 , … , a j ) 的边。同时 i , i + 1 i , i + 1 两个点之间会有一条边权为 p p 的边。
2 ≤ n ≤ 2 × 10 5 2 ≤ n ≤ 2 × 10 5 ,1 ≤ a i , p ≤ 10 9 1 ≤ a i , p ≤ 10 9
Solution
显然我们发现:如果序列 a i , a i + 1 , … , a j a i , a i + 1 , … , a j 中最小值为 k k ,并且所有数字都是 k k 的倍数,那么这些点都是联通的,边权为 k k 。
所以只需要判断一下满足 gcd ( a i , a i + 1 , … , a j ) = min ( a i , a i + 1 , … , a j ) gcd ( a i , a i + 1 , … , a j ) = min ( a i , a i + 1 , … , a j ) 的所有极大区间 [ i , j ] [ i , j ] 即可。
具体做法是找到所有比 p p 小的 a i a i ,然后向两边扩展到极大,把这一段覆盖掉,如果遇到已经被覆盖的就不需要覆盖了。注意如果一个点从左边被覆盖了,还能从右边覆盖一次。
时间复杂度 O ( n log n ) O ( n log n )
CF1665D
交互题,你需要猜出一个数字 x x 。
每次你可以给出 a , b a , b ,然后你会得到 gcd ( x + a , x + b ) gcd ( x + a , x + b ) 的值,你最多可以进行这样的操作 30 30 次。
1 ≤ x ≤ 10 9 1 ≤ x ≤ 10 9 ,1 ≤ a , b ≤ 2 × 10 9 1 ≤ a , b ≤ 2 × 10 9
Solution
显然 gcd ( x + a , x + b ) = gcd ( x + a , b − a ) gcd ( x + a , x + b ) = gcd ( x + a , b − a ) 。
这样我们就可以猜出 x x 在二进制下的每一位。
我们从低位到高位猜,假设现在猜的是从右往左第 i i 位,那么我们现在就已经知道了右边 i − 1 i − 1 位,这些位的数值的和记作 y y ,令 a = 2 i − 1 − y a = 2 i − 1 − y ,b = 2 i + 2 i − 1 − y b = 2 i + 2 i − 1 − y 。假设返回的数是 m m 。 如果 m = 2 i m = 2 i ,也就是说,在第 i i 位加上了 1 1 会产生进位,那么这一位就是 1 1 ,反之这一位就是 0 0 。
这样刚好需要猜 30 30 次。
但是有没有更加优秀的做法呢?
由于 gcd ( x + a , x + b ) = gcd ( x + a , b − a ) gcd ( x + a , x + b ) = gcd ( x + a , b − a ) ,所以 ( b − a ) ∣ gcd ( x + a , x + b ) ⟺ ( b − a ) ∣ ( x + a ) ( b − a ) ∣ gcd ( x + a , x + b ) ⟺ ( b − a ) ∣ ( x + a )
考虑构造一个序列 t t ,使序列 t t 中的数字两两互质,并且这些数字尽可能小,令 a = ∏ t a = ∏ t 有 10 9 ≤ a ≤ 2 × 10 9 10 9 ≤ a ≤ 2 × 10 9 。
令 m = t max m = t max ,枚举 i i 从 1 1 到 m m ,询问得到 gcd ( x + a + i , x + i ) = gcd ( x + i , a ) gcd ( x + a + i , x + i ) = gcd ( x + i , a ) 的值。
如果 t i ∣ gcd ( x + i , a ) t i ∣ gcd ( x + i , a ) ,那么 t i ∣ x + a + i t i ∣ x + a + i ,我们就能得到 x ≡ − i ( mod t i ) x ≡ − i ( mod t i ) 。然后直接使用中国剩余定理合并答案,由于 x ≤ 10 9 ≤ a ≤ 2 × 10 9 x ≤ 10 9 ≤ a ≤ 2 × 10 9 ,所以答案只有一种可能。
当 t = { 4 , 5 , 7 , 9 , 11 , 13 , 17 , 19 , 23 } t = { 4 , 5 , 7 , 9 , 11 , 13 , 17 , 19 , 23 } ,此时满足条件。
这样只需要询问 23 23 次。
但是我们发现,枚举 i i 从 1 1 到 23 23 的时候肯定都会得到 x x 对于 t t 中任意一个元素取模的答案,所以如果在前 22 22 次的猜测中都没有得到答案,那么肯定在 i = 23 i = 23 的时候能得到答案。
所以这样只需要询问 22 22 次。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具