题意简述
给出自然数 a a a 和质数 p , q p,q p , q ,求解 x q ≡ a ( m o d p ) x^q\equiv a\pmod p x q ≡ a ( m o d p ) ,输出任一符合条件的 x ∈ [ 0 , p ) x\in [0,p) x ∈ [ 0 , p ) 即可,无解输出 -1
。
T ≤ 100 T\le 100 T ≤ 1 0 0 组数据,p , q ≤ 1 0 18 p,q\le 10^{18} p , q ≤ 1 0 1 8 ,0 ≤ a < p 0\le a<p 0 ≤ a < p 。
解法
接下来的题解会尽量依照正向的思路去写,笔者就是被反向思路写的官方题解打蒙的……
本题构造思路太神仙了,笔者认为实用性不强,在考场上可能很难自主复现,估计也考不着 。Anyway, % 127。
简单解
出题人说这是高次剩余板子,可是看数据范围,朴素离散对数显然不能过,时间复杂度达到 O ( T p ) O(T\sqrt p) O ( T p ) 。如果我们需要上 BSGS 算法,模数不可以是 p p p 级别的。
考虑费马小定理,有 a ≡ a m ( p − 1 ) + 1 ( m o d p ) a\equiv a^{m(p-1)+1}\pmod p a ≡ a m ( p − 1 ) + 1 ( m o d p ) 。
那么就可能有简单解:如果存在 m m m 满足 q ∣ m ( p − 1 ) + 1 q|m(p-1)+1 q ∣ m ( p − 1 ) + 1 ,则方程有解
x ≡ a m ( p − 1 ) + 1 q ( m o d p ) x\equiv a^{\frac{m(p-1)+1}{q}} \pmod p
x ≡ a q m ( p − 1 ) + 1 ( m o d p )
就是直接在指数上除以 q q q 。
考虑出现这种情况的条件:发现 q ⊥ p − 1 q\perp p-1 q ⊥ p − 1 ,上述解即化为
x ≡ a q − 1 ( m o d p − 1 ) ( m o d p ) x\equiv a^{q^{-1}\pmod{p-1}} \pmod p
x ≡ a q − 1 ( m o d p − 1 ) ( m o d p )
判无解
然后判断一下是否无解。
为了便于判断,令 q K t = p − 1 q^Kt=p-1 q K t = p − 1 (显然指数应该放在质数 q q q 上)。判断完上面 K = 0 K=0 K = 0 的情况,接下来我们有 K ≥ 1 K\ge 1 K ≥ 1 ,q ∣ ( p − 1 ) q|(p-1) q ∣ ( p − 1 ) 。
若有解 x x x ,则
x p − 1 ≡ 1 ( m o d p ) x^{p-1}\equiv 1\pmod p
x p − 1 ≡ 1 ( m o d p )
a p − 1 q ≡ 1 ( m o d p ) a^{\frac{p-1}{q}}\equiv 1\pmod p
a q p − 1 ≡ 1 ( m o d p )
a q K − 1 t ≡ 1 ( m o d p ) a^{q^{K-1}t}\equiv 1\pmod p
a q K − 1 t ≡ 1 ( m o d p )
若不满足上述条件,则无解。
由判定的同余式得到的启示
发现上面的写法和费马小定理的形式有些像,考虑用类似于简单解的形式,找出通用解。
假设我们已经有 k k k 满足 a q k t ≡ 1 ( m o d p ) a^{q^kt}\equiv 1\pmod p a q k t ≡ 1 ( m o d p ) (注意区分 K K K 和 k k k ),且能找到 m m m 满足 q ∣ m q k t + 1 q|mq^kt+1 q ∣ m q k t + 1 ,则由 a ≡ a m q k t + 1 ≡ ( a m q k t + 1 q ) q ( m o d p ) a\equiv a^{mq^kt+1}\equiv (a^{\frac{mq^kt+1}{q}})^q\pmod p a ≡ a m q k t + 1 ≡ ( a q m q k t + 1 ) q ( m o d p ) ,有解
x ≡ a m q k t + 1 q ( m o d p ) x\equiv a^{\frac{mq^kt+1}{q}}\pmod p
x ≡ a q m q k t + 1 ( m o d p )
发现能找到 m m m 的条件是 q k t ⊥ q q^kt\perp q q k t ⊥ q 。所以 k = 0 k=0 k = 0 ,解化为
x ≡ a q − 1 ( m o d t ) ( m o d p ) x\equiv a^{q^{-1}\pmod{t}}\pmod p
x ≡ a q − 1 ( m o d t ) ( m o d p )
由 a q K − 1 t ≡ 1 ( m o d p ) a^{q^{K-1}t}\equiv 1\pmod p a q K − 1 t ≡ 1 ( m o d p ) ,我们已经有一个满足假设的 k = K − 1 k=K-1 k = K − 1 。我们只要让它不断地减小,直到它等于 0 0 0 。在过程中,a q K − 1 t a^{q^{K-1}t} a q K − 1 t 最后会变化为 a 0 a_0 a 0 ,最终有 a 0 t ≡ 1 ( m o d p ) a_0^t\equiv 1\pmod p a 0 t ≡ 1 ( m o d p ) ,容易求解 x 0 t ≡ a 0 ( m o d p ) x_0^t\equiv a_0\pmod p x 0 t ≡ a 0 ( m o d p ) 。求出最后的解 x 0 x_0 x 0 ,我们再以一种方式回带即可。
当然,在 K = 1 K=1 K = 1 时我们就不需要再去减小了,因此接下来 K ≥ 2 K\ge 2 K ≥ 2 ,即 q ≤ p q\le\sqrt p q ≤ p 。
(讲完算法之后,会发现这个位置对时间复杂度分析是重要的,因为这时 q q q 已经较小,我们可以直接对满足 w q ≡ 1 ( m o d p ) w^q\equiv 1\pmod p w q ≡ 1 ( m o d p ) 的 w w w 做 BSGS。)
让 k k k 减一
我们已经有 a q k t ≡ 1 ( m o d p ) a^{q^kt}\equiv 1\pmod p a q k t ≡ 1 ( m o d p ) 。令 v ≡ a q k − 1 t ( m o d p ) v\equiv a^{q^{k-1}t}\pmod p v ≡ a q k − 1 t ( m o d p ) ,则 v q ≡ a q k t ≡ 1 ( m o d p ) v^q\equiv a^{q^kt}\equiv 1\pmod p v q ≡ a q k t ≡ 1 ( m o d p ) 。
你可以判一下,如果此时的 v = 1 v=1 v = 1 ,那么 k k k 减一时不用做其他变化,直接 continue
即可。
否则我们希望找到一个 a ′ q k − 1 t ≡ a q k t ≡ 1 ( m o d p ) a'^{q^{k-1}t}\equiv a^{q^kt}\equiv 1\pmod p a ′ q k − 1 t ≡ a q k t ≡ 1 ( m o d p ) ,用 a ′ a' a ′ 替换 a a a 。
考虑用 a ′ ≡ z q a ( m o d p ) a'\equiv z^qa\pmod p a ′ ≡ z q a ( m o d p ) 来描述这种变换(这样子设,回带 x x x 是简明的)。
a ′ q k − 1 t ≡ ( z q a ) q k − 1 t ≡ z q k t a q k − 1 t ≡ z q k t v ≡ 1 ( m o d p ) a'^{q^{k-1}t}\equiv (z^qa)^{q^{k-1}t}\equiv z^{q^kt}a^{q^{k-1}t}\equiv z^{q^kt}v\equiv 1\pmod p
a ′ q k − 1 t ≡ ( z q a ) q k − 1 t ≡ z q k t a q k − 1 t ≡ z q k t v ≡ 1 ( m o d p )
z q k t ≡ v − 1 ( m o d p ) z^{q^kt}\equiv v^{-1}\pmod p
z q k t ≡ v − 1 ( m o d p )
由于 q q q 小,我们想能不能直接找到一个 Z Z Z ,对它求 b b b 满足 Z b ≡ v − 1 ( m o d p ) Z^b\equiv v^{-1}\pmod p Z b ≡ v − 1 ( m o d p ) (假设一),并且 Z q ≡ 1 ( m o d p ) Z^q\equiv 1\pmod p Z q ≡ 1 ( m o d p ) (假设二)……?
在构造 Z Z Z 的路上狂奔
回到最初的费马小定理,对于任一个 w w w ,我们都有 w q K t ≡ w p − 1 ≡ 1 ( m o d p ) w^{q^Kt}\equiv w^{p-1}\equiv 1\pmod p w q K t ≡ w p − 1 ≡ 1 ( m o d p ) 。要满足假设二,我们取一个
Z ≡ w q K − 1 t ( m o d p ) Z\equiv w^{q^{K-1}t}\pmod p
Z ≡ w q K − 1 t ( m o d p )
即可。
假设一我们尝试用 BSGS 算法求出 b b b 来完成。由 Z q ≡ 1 ( m o d p ) Z^q\equiv 1\pmod p Z q ≡ 1 ( m o d p ) 联系到 v q ≡ 1 ( m o d p ) v^q\equiv 1\pmod p v q ≡ 1 ( m o d p ) 这一重要的性质,可以证明 Z ≠ 1 Z\neq 1 Z = 1 且 v ≠ 1 v\neq 1 v = 1 时都可以求出 b b b 。也就是说,我们在选取 w w w 时,要令 w q K − 1 t ≢ 1 ( m o d p ) w^{q^{K-1}t}\not\equiv 1\pmod p w q K − 1 t ≡ 1 ( m o d p ) 。
然后我们来用 Z Z Z 生成 z z z 。
z q k t ≡ Z b ≡ w q K − 1 t b ( m o d p ) z^{q^kt}\equiv Z^b\equiv w^{q^{K-1}tb}\pmod p
z q k t ≡ Z b ≡ w q K − 1 t b ( m o d p )
z ≡ w q K − 1 − k b ( m o d p ) z\equiv w^{q^{K-1-k}b}\pmod p
z ≡ w q K − 1 − k b ( m o d p )
然后再用 z z z 计算 a ′ a' a ′ 。如此循环,让 k k k 不断减一,直到 0 0 0 。
回带
我们最终求出了 x 0 q ≡ a 0 ( m o d p ) x_0^q\equiv a_0\pmod p x 0 q ≡ a 0 ( m o d p ) 的一个解,我们要回去求 x q ≡ a ( m o d p ) x^q\equiv a\pmod p x q ≡ a ( m o d p ) 。
根据 a 0 ≡ z 0 q a 1 ( m o d p ) a_0\equiv z_0^qa_1\pmod p a 0 ≡ z 0 q a 1 ( m o d p ) ,我们有
x 0 q ≡ z 0 q a 1 ( m o d p ) x_0^q\equiv z_0^qa_1\pmod p
x 0 q ≡ z 0 q a 1 ( m o d p )
( x 0 z 0 ) q ≡ a 1 ( m o d p ) (\frac{x_0}{z_0})^q\equiv a_1\pmod p
( z 0 x 0 ) q ≡ a 1 ( m o d p )
所以可以有解
x 1 ≡ x 0 z 0 ( m o d p ) x_1\equiv\frac{x_0}{z_0}\pmod p
x 1 ≡ z 0 x 0 ( m o d p )
依此类推,可以有
x ≡ x 0 ∏ z ( m o d p ) x\equiv\frac{x_0}{\prod z}\pmod p
x ≡ ∏ z x 0 ( m o d p )
时间复杂度分析
对于特判等细节处,显然是 O ( log p ) O(\log p) O ( log p ) 的。
然后我们做的第一件非 O ( log p ) O(\log p) O ( log p ) 的事是找到一个合法的 w w w 。回顾对 w w w 的限制:w q K − 1 t ≡ w p − 1 q ≢ 1 ( m o d p ) w^{q^{K-1}t}\equiv w^{\frac{p-1}{q}}\not\equiv 1\pmod p w q K − 1 t ≡ w q p − 1 ≡ 1 ( m o d p ) 。显然质数 p p p 的原根就满足这个性质,原根的指数小于 p − 1 p-1 p − 1 的话 m o d p \bmod p m o d p 后必不等于 1 1 1 。所以我们找到的 w w w 完全可以不超过 p p p 的最小原根,大小是 O ( p 1 4 ) O(p^{\frac{1}{4}}) O ( p 4 1 ) 的。
接下来,我们不断让 k k k 减一,显然 k k k 的级别是 O ( log q p ) O(\log_q p) O ( log q p ) 的。然后,我们要跑若干次 BSGS。注意到次数小于 q q q ,并且要做 BSGS 的条件是 K ≥ 2 K\ge 2 K ≥ 2 ,q ≤ p q\le\sqrt p q ≤ p 。所以 BSGS 单次复杂度 O ( q ) O(\sqrt q) O ( q ) 也是 O ( p 1 4 ) O(p^{\frac{1}{4}}) O ( p 4 1 ) 。
综上,时间复杂度是 O ( T p 1 4 log p ) O(Tp^{\frac{1}{4}}\log p) O ( T p 4 1 log p ) 的。看起来好像不能光速幂,而且这个复杂度已经可以过了。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 #include <bits/stdc++.h> using namespace std;typedef long long ll;typedef __int128_t i128;int T; ll A, Q, P;ll gcd (ll x, ll y) { while (y) { ll t (x % y) ; x = y; y = t; } return x; }ll pw (ll b, ll p, ll m) { ll a (1 ) ; while (p) { if (p & 1 ) a = static_cast <i128>(a) * b % m; b = static_cast <i128>(b) * b % m; p >>= 1 ; } return a; }void exgcd (ll a, ll b, ll& x, ll& y) { if (!b) x = 1 , y = 0 ; else exgcd (b, a % b, y, x), y -= a / b * x; }ll inv (ll a, ll p) { ll x (0 ) , y (0 ) ; exgcd (a, p, x, y); return (x % p + p) % p; }class BSGSA { private : unordered_map<ll, int > mp; ll bse, dvs, rng; public : BSGSA (ll b, ll p, ll m) : bse (b), dvs (m), rng (p) { ll a (pw(b, rng, m)) ; for (ll i (1 ), j (a); i <= rng; ++i, j = static_cast <i128>(j) * a % m) mp[j] = i; } int query (ll x) { for (ll i (0 ), j (x);; ++i, j = static_cast <i128>(j) * bse % dvs) if (mp[j]) return mp[j] * rng - i; return -1 ; } };ll solve (ll a, ll q, ll p) { ll K (0 ) , t (p - 1 ) ; while (t % q == 0 ) ++K, t /= q; if (K == 0 ) return pw (a, inv (q, p - 1 ), p); if (pw (a, (p - 1 ) / q, p) != 1 ) return -1 ; ll iv (1 ) ; if (K > 1 ) { ll Z, w (1 ); while ((Z = pw (w, (p - 1 ) / q, p)) == 1 ) ++w; BSGSA bsgs (Z, sqrt(q) + 2 , p) ; for (int k (K - 1 ); k; --k) { ll v (pw(a, t * pw(q, k - 1 , p), p)) ; if (v == 1 ) continue ; ll b (bsgs.query(inv(v, p))) ; ll z (pw(w, b * pw(q, K - k - 1 , p), p)) ; a = static_cast <i128>(a) * pw (z, q, p) % p; iv = static_cast <i128>(iv) * z % p; } } return static_cast <i128>(pw (a, inv (q, t), p)) * inv (iv, p) % p; }int main () { ios::sync_with_stdio (false ); cin.tie (nullptr ); cin >> T; while (T--) { cin >> A >> Q >> P; cout << solve (A, Q, P) << endl; } return 0 ; }
要特判 a = 0 a=0 a = 0 ,输出 0 0 0 。
Updated on 2023.8.22.