文章目录
BSGS & exBSGS
Description
给定 a , b , p a,b,p a,b,p,你需要找到最小的满足 a x ≡ b ( m o d p ) a^x \equiv b \pmod p ax≡b(modp) 的 x x x。
T T T 组数据, ∑ p ≤ 5 × 1 0 6 \sum \sqrt p \le 5 \times 10^6 ∑p≤5×106。
算法一(BSGS: 保证 gcd ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1)
令 B = ⌈ p ⌉ B=\lceil \sqrt p \rceil B=⌈p⌉, t = a B t=a^B t=aB。
我们先将 a 0 , a 1 , ⋯ , a B a^0,a^1,\cdots,a^B a0,a1,⋯,aB 分别压入哈希表中,接着枚举 i = 0 , 1 , ⋯ i=0,1,\cdots i=0,1,⋯,同时算出 b t i \frac {b} {t^{i}} tib 在模意义下的值。如果该值在哈希表中出现过,则我们就得到了答案。
时间复杂度 O ( B ) O(\sqrt B) O(B)。逆元可以用扩展欧几里得算法求解(在 p p p 为质数的时候也可以用费马小定理),哈希表可以使用 unordered_map 来实现。
算法二(exBSGS)
若不保证 gcd ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1,那么就无法算出 b t i \frac {b} {t^i} tib 在模意义下的值了,因为 t i t^i ti 在模意义下可能不存在逆元。所以我们考虑将其转化为 gcd ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1 的情况,这样就能直接套用算法一了。
考虑计算出 d = gcd ( a , p ) d=\gcd(a,p) d=gcd(a,p),那么问题就转化为求出最小的 x x x 使得 ( a d ) a x − 1 ≡ b p ( m o d p d ) (\frac a d)a^{x-1} \equiv \frac b p\pmod {\frac {p} d} (da)ax−1≡pb(moddp)。注意到 a d \frac a d da 与 p d \frac p d dp 是互质的,所以我们可以计算出 a d \frac a d da 的逆元并将其提到右边,这样就转化为了一个本质相同而规模减小的子问题 a x − 1 ≡ b d × a d − 1 ( m o d p d ) a^{x-1} \equiv {\frac b d}\times {\frac a d}^{-1} \pmod {\frac p d} ax−1≡db×da−1(moddp),可以递归解决。
特别的,当 d = 1 d=1 d=1 时,我们直接调用 BSGS 就行了。此外,注意特判 b = 1 b=1 b=1 或 p = 1 p=1 p=1 的情况,此时应直接返回 0 0 0。同时,要注意假设目前已经递归到了第 k k k 层(刚开始是第 0 0 0 层),那么真正的答案应该还要再加上 k k k。
注意到每次 p p p 都至少除以 2 2 2,所以 p p p 至多会变化 log p \log p logp 次,而每次都要通过辗转相除计算一次 gcd,所以总复杂度是 O ( log 2 p + p ) O(\log^2 p+\sqrt p) O(log2p+p) 的。
由于 unordered_map 的巨大常数,洛谷上会轻微卡常。
Lucas & exLucas
Description
给定 n , m , p n,m,p n,m,p,求 ( n m ) mod p {n \choose m} \ \text{mod} \ p (mn) mod p。
1 ≤ n , m ≤ 1 0 18 , 1 ≤ p ≤ 1 0 6 1 \le n,m \le 10^{18},1 \le p \le 10^6 1≤n,m≤1018,1≤p≤106
算法一(Lucas: 保证 p p p 为质数)
首先,如果 n , m < p n,m<p n,m<p,那么可以直接阶乘逆元求解。那么 n , m ≥ p n,m \ge p n,m≥p 的话该怎么办呢?
Lucas 定理给出
( n m ) ≡ ( ⌊ n p ⌋ ⌊ m p ⌋ ) × ( n mod p m mod p ) ( m o d p ) {n \choose m} \equiv {{\lfloor \frac n p \rfloor} \choose {\lfloor \frac m p \rfloor}} \times {{n \ \text{mod} \ p} \choose m \ \text{mod} \ p} \pmod p (mn)≡(⌊pm⌋⌊pn⌋)×(m mod pn mod p)(modp)
递归求解即可。
时间复杂度 O ( p + log p n ) O(p+\log_p n) O(p+logpn)。
算法二(exLucas: 不保证 p p p 为质数)
首先考虑对 p p p 进行质因数分解,将其拆分为 p = ∏ i = 1 k a i b i p=\prod_{i=1}^k a_i^{b_i} p=∏i=1kaibi 的形式( ∀ i ∈ [ 1 , p ] \forall i \in [1,p] ∀i∈[1,p], a i a_i ai 为质数),那么只要我们对于每个 i i i 求出了 ( n m ) {n \choose m} (mn) 对 a i b i a_i^{b_i} aibi 取模后的值,通过 CRT 合并就能得到答案了。所以关键在于,当模数为某个质数的若干次方 p q p^q pq 的时候,如何算出组合数 ( n m ) {n \choose m} (mn) 在模意义下的值。
考虑计算出 n ! , m ! , ( n − m ) ! n!,m!,(n-m)! n!,m!,(n−m)! 中分别包含多少个质因子 p p p。假设分别有 x , y , z x,y,z x,y,z 个,那么 ( n m ) {n \choose m} (mn) 中就包含了 x − y − z x-y-z x−y−z 个质因子 p p p。那么,如果 x − y − z ≥ q x-y-z \ge q x−y−z≥q,那么显然 ( n m ) ≡ 0 ( m o d p q ) {n \choose m} \equiv 0 \pmod {p^q} (mn)≡0(modpq)。否则,我们考虑分别求出 n ! , m ! , ( n − m ) ! n!,m!,(n-m)! n!,m!,(n−m)! 去掉所有质因子 p p p 后的值 u , v , w u,v,w u,v,w,那么答案即为 u ! v ! w ! \frac {u!} {v!w!} v!w!u! 模 p q − ( x − y − z ) p^{q-(x-y-z)} pq−(x−y−z) 再乘上 p x − y − z p^{x-y-z} px−y−z 的值,显然可以通过扩展欧几里得算法求出。
所以关键在于,如何求出把 n ! n! n! 中的所有质因子 p p p 去掉后的值 f ( n , p ) f(n,p) f(n,p)。不难发现, f ( n , p ) f(n,p) f(n,p) 的组成分为三个部分,其中第一个部分是 [ 1 , n ] [1,n] [1,n] 中 p p p 的倍数,第二个部分是 [ 1 , p × ⌊ n p ⌋ ] [1,p \times \lfloor \frac {n} {p} \rfloor] [1,p×⌊pn⌋] 中非 p p p 的倍数,第三个部分就是 ( p × ⌊ n p ⌋ , n ] (p \times \lfloor \frac {n} {p} \rfloor,n] (p×⌊pn⌋,n] 中的所有数。对于第一个部分,我们可以递归求解;对于第二个部分,不难发现其乘积由若干个连续段组成,而根据威尔逊定理,其中任何一个连续段的乘积均为 − 1 -1 −1,所以这一部分的贡献就是 ( − 1 ) ⌊ n p ⌋ (-1)^{\lfloor \frac n p \rfloor} (−1)⌊pn⌋;而对于第三个部分,注意到其乘积在模意义下与 ( n mod p ) ! (n \ \text{mod} \ p)! (n mod p)! 相等,通过预处理出各个数在模意义下的的阶乘,每次就可以 O ( 1 ) O(1) O(1) 调用了。
总时间复杂度与 O ( p log p ) O(p \log p) O(plogp) 同级。