題目傳送門
Subtask 1
直接模擬。
Subtask 2
BSGS算法模板。
Subtask 3
考慮模 $m$ 的任意一個原根 $g$。
假設 $g^{ra} \equiv x \pmod {m}, g^{rb} \equiv y \pmod{m}$ 。
那麼原題的方程等價於方程 $a \cdot ra \equiv rb \pmod {\varphi(m)}$。
它等價於 $x \cdot ra - y\cdot \varphi(m) = rb$。
設 $d = \varphi(m)$。
它存在滿足條件的解當且僅當 $(ra, d) \mid rb$。
這個條件仍然不好處理,因爲我們難以求出 $rb$。
考慮這樣一個條件 $(ra, d) \mid (rb, d)$。
我們來證明,滿足 $(ra, d) \mid rb$ 當且僅當 $(ra, d) \mid (rb, d)$。
充分性顯然。
考慮必要性,因爲 $((ra,d), (rb,d)) = (ra, rb, d) = ((ra, d) , rb) = (ra, d)$。
所以有 $(ra, d) \mid (rb, d)$。
現在的問題是如何求 $(ra, d)$。
引理 設 $g$ 爲模 $m$ 意義下的一個原根 ,如果 $g^{ra} \equiv a \pmod {m}$,設 $\delta_m(a) = d$ ,那麼有 $(ra, \varphi(m)) d = \varphi(m)$.
證明 因爲有 $\left( g^{ra}\right)^d \equiv 1\pmod{m}$,所以 $\varphi(m) | ra \cdot d$。
那麼有 $ra \cdot d \equiv 0 \pmod {\varphi(m)}$.
所以有 $d \equiv 0 \pmod{\frac{\varphi(m)}{(\varphi(m), ra)}}$.
因爲 $d$ 是滿足條件的最小正整數,所以有 $d = \frac{\varphi(m)}{(\varphi(m), ra)}$。
所以 $(\varphi(m), ra) d = \varphi(m)$。
因此我們把問題轉化爲求階。
衆所周知,階是 $\varphi(m)$ 的約數,所以我們暴力枚舉所有因子能通過這個subtask。
Subtask 4
因爲 $p$ 隨機,所以期望的因子個數只有幾千,做法同 Subtask 3。
Subtask 5
騙暴力選手去卡常。
Subtask 6
我們考慮優化求階的做法。
引理 設 $d = \delta_m(x)$,如果 $d_0$ 滿足 $x^{d_0} \equiv 1\pmod {m}$,那麼有 $d | d_0$。
證明 設 $d_0 = qd + r\ (0 < r < d)$。那麼有 $x^{qd + r} \equiv (x^{d})^q x^r \equiv x^r \equiv 1\pmod{m}$。因爲 $d$ 是最小的正整數滿足 $x^{d} \equiv 1 \pmod {m}$,但 $r$ 是更小的滿足條件的正整數,這和階的定義矛盾。
初始令 $d =\varphi(m)$。根據歐拉定理,我們知道一定有 $x^{d} \equiv 1 \pmod{m}$。設 $d = k\delta_m(x)$
考慮枚舉任意一個 $\varphi(m)$ 的質因子 $p$,如果滿足 $p \mid d$,並且 $x^{d / p} \equiv 1 \pmod {m}$。 那麼有 $p \mid k$,我們令 $d' = d / p$ 繼續執行這個過程,直到不存在滿足條件的 $p$。
由於乘法取模我們可以使用 __int128 ,所以時間複雜度 $O(T \log^2 V + n^{1/4})$。
如果同時求 $(ra, \varphi(m)), (rb, \varphi(m))$ 可能會被卡常。
Subtask 7
我們注意到,我們沒有必要求 $(rb, \varphi(m))$。
設 $d = \varphi(m)$。
$(ra, d) | (rb, d) $ 等價於 $\frac{d}{(rb, d)}| \frac{d}{(ra, d)}$。
因此我們只用判斷 $b^{e}$ 模 $m$ 的餘數是否爲1就行了。
其中 $e$ 是最小的正整數滿足 $a^e \equiv 1 \pmod{m}$,即 $a$ 模 $m$ 的階。
吐槽
- 不知道爲什麼很多人覺得 $(ra, d) \mid rb$ 當且僅當 $(ra, d) \mid (rb, d)$ 非常地顯然,可能是我數學比較菜,覺得不是那麼顯然,需要說明一下。
- 成功區分了會求階和不會求階的選手
- 開始想卡掉求 2 次階的做法,因爲 F 很難,爲了降低比賽難度,所以被要求這裏不卡常,不過好像卡不卡區分度都是一樣的。
- 事後發現,二進制分組和 long double 快速乘均可以輕鬆跑進兩倍標程序時限內,感覺我對卡常一無所知,我似乎還忘了卡 long double 快速乘。(雖然我並不知道能個不能卡)。兩倍常數還想卡?
- 洛谷怎麼最大隻支持 100 組數據
Code
#include <bits/stdc++.h> using namespace std; typedef bool boolean; #define ll long long #define ull unsigned long long template <typename T> T add(T a, T b, T m) { return ((a += b) >= m) ? (a - m) : (a); } template <typename T> void pcopy(T* pst, const T* ped, T* pval) { for ( ; pst != ped; *(pst++) = *(pval++)); } ll mul(ll a, ll b, ll m) { return ((__int128)a) * b % m; /* ll rt = 0, pa = a; for ( ; b; b >>= 1, pa = add(pa, pa, m)) if (b & 1) rt = add(rt, pa, m); return rt; */ } ll qpow(ll a, ll p, ll m) { ll rt = 1, pa = a; for ( ; p; p >>= 1, pa = mul(pa, pa, m)) if (p & 1) rt = mul(rt, pa, m); return rt; } ll gcd(ll a, ll b) { return (b) ? (gcd(b, a % b)) : (a); } ll randLL() { static ull seed = 998244353, msk = (1ull << 61) - 1; return (signed ll) ((seed = seed * seed + seed * 3 + 233) & msk); } boolean miller_rabin(ll n) { static int T = 25; static const int pri[10] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29}; if (!(n & 1)) return n == 2; if (n < 1000) { for (int p = 2; p * p <= n; p++) if (!(n % p)) return false; return true; } for (int i = 0; i < 10; i++) { if (n == pri[i]) { return true; } else if (!(n % pri[i])) { return false; } } ll d = n - 1; int s = 0; while (!(d & 1)) s++, d >>= 1; for (int t = 0; t < T; t++) { ll b = randLL() % n; if (!b) continue; ll tmp = qpow(b, d, n); if (tmp == 1 || tmp == n - 1) continue; for (int i = 0; i < s; i++) { tmp = mul(tmp, tmp, n); if (tmp == n - 1) goto nextTurn; if (tmp == 1 || tmp == 0) return false; } if (tmp != 1) return false; nextTurn:; } return true; } ll pollard_rho(ll x) { // cerr << x << '\n'; ll a, b, c, g; if (!(x & 1)) return 2; while (true) { b = a = randLL() % x; c = randLL() % 127 % x; do { a = add(mul(a, a, x), c, x); b = add(mul(b, b, x), c, x); b = add(mul(b, b, x), c, x); g = gcd(b - a, x); (g < 0) ? (g = -g) : (0); if (g == x) break; if (g > 1) return g; } while (a != b); } assert(false); return 0; } void get_primary_factors(ll x, vector<ll>& rt) { if (x == 1) { return; } if (miller_rabin(x)) { rt.push_back(x); return; } ll a = pollard_rho(x); get_primary_factors(a, rt); get_primary_factors(x / a, rt); } vector< pair<ll, int> > get_primary_factor(vector<ll>& vec) { vector< pair<ll, int> > rt; if (vec.empty()) return rt; sort(vec.begin(), vec.end()); vector<ll>::iterator it = vec.begin(); rt.push_back(make_pair(*it, 1)); for (it = it + 1 ; it != vec.end(); it++) if (*it == rt.back().first) rt.back().second++; else rt.push_back(make_pair(*it, 1)); return rt; } /// Template ends typedef vector<pair<ll, int>> factor; factor get_factor(ll m) { vector<ll> tmp; get_primary_factors(m, tmp); return get_primary_factor(tmp); } int T; ll m, phim; factor fac; int main() { scanf("%lld%d", &m, &T); fac = get_factor(m); fac = get_factor(phim = m / fac[0].first * (fac[0].first - 1)); ll a, b, d; while (T--) { scanf("%lld%lld", &a, &b); d = phim; for (auto par : fac) { while (!(d % par.first) && qpow(a, d / par.first, m) == 1) d /= par.first; } if (qpow(b, d, m) == 1) { puts("Yes"); } else { puts("No"); } } return 0; }