Tenka1-2017 F ModularPowerEquation!!【数论、扩欧】
给定自然数 \(a\) 和正整数 \(m\),求 \(k<2\cdot 10^{18}\) 使得 \(a^k\equiv k\pmod m\)。\(T\) 组数据。
\(T\le 100,a,m\le 10^9\)。
众所周知,\(a^k\bmod m\) 在不循环部分之后进入长度为 \(\varphi(m)\) 的约数的循环。
于是我们解方程均只考虑 \(\ge m\varphi(m)\) 的解,就不用考虑开头部分了。
考虑构造一个 \(y\),使得存在 \(x\),其中 \(x\equiv a^y\pmod m\),\(x\equiv y\pmod{\varphi(m)}\),可以得到 \(a^x\equiv a^y\equiv x\pmod m\)。
需要 \(a^y\equiv y\pmod{\gcd(m,\varphi(m))}\),这是一个递归的子问题。用扩欧可以从 \(y\) 算出 \(x\)。
复杂度瓶颈在算 \(\varphi\),先筛出 \(m\) 的质因子再求,\(O(\frac{T\sqrt m}{\log m})\)。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 31625, M = 3403;
template<typename T>
void read(T &x){
int ch = getchar(); x = 0; bool f = false;
for(;ch < '0' || ch > '9';ch = getchar()) f |= ch == '-';
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
if(f) x = -x;
} int ksm(int a, LL b, int mod){
int res = 1;
for(;b;b >>= 1, a = (LL)a * a % mod)
if(b & 1) res = (LL)res * a % mod;
return res;
}
int T, a, m, pri[M], tot, pr[15], cnt;
bool notp[N];
void init(int m){
notp[0] = notp[1] = true;
for(int i = 2;i <= m;++ i){
if(!notp[i]) pri[tot++] = i;
for(int j = 0;j < tot && i * pri[j] <= m;++ j){
notp[i * pri[j]] = true;
if(!(i % pri[j])) break;
}
}
} void fact(int x){ cnt = 0;
for(int i = 0;i < tot && pri[i] * pri[i] <= x;++ i) if(!(x % pri[i])){
x /= pri[i]; pr[cnt++] = pri[i]; while(!(x % pri[i])) x /= pri[i];
} if(x > 1) pr[cnt++] = x;
} int phi(int x){
int ans = x;
for(int i = 0;i < cnt && pr[i] * pr[i] <= x;++ i) if(!(x % pr[i])){
ans = ans / pr[i] * (pr[i] - 1); x /= pr[i];
while(!(x % pr[i])) x /= pr[i];
} if(x > 1) ans = ans / x * (x - 1);
return ans;
} int exgcd(int a, int b, int &x, int &y){
if(!b){x = 1; y = 0; return a;}
int d = exgcd(b, a % b, y, x);
y -= a / b * x; return d;
} LL calc(int a, int m){
if(m == 1) return 1;
int n = phi(m), x, y, d = exgcd(n, m, x, y);
LL u = calc(a, d), v = ksm(a, u, m);
LL ret = x * (v - u) / d % m, mod = (LL)m * n;
return (n * ret + u + mod) % mod + mod;
}
int main(){
read(T); init(N-1);
while(T --){
read(a); read(m); a %= m; fact(m);
printf("%lld\n", calc(a, m));
}
}