题意:
求解方程A^x=B (mod C)在[0,C)中的最小解;
C<=10^9;
题解:
此题C并不是质数,所以要用一种叫做EXBSGS的东西来解;
考虑BSGS的适用条件,主要是在于A^k也就是A不一定对于C有逆元;
那么约下去一些怎么样?
令d=gcd(A,C),那么一定有 d|B或者x=0,B=1;
x=0的情况比较特殊,直接特判即可;
那么若没有d|B则无解;
而如果同时除一个B之后,方程即为A/d*A^(x-1)=B/d (mod C/d);
多次执行该操作,直到gcd(A,C/d1*d2*d3*...*dk)=1为止;
设P=d1*d2*d3*...*dk这一大坨;
此时方程为(A^k/P)*A^(x-k)=B/P (mod C/P);
这个方程是支持BSGS的!直接套用即可;
然后解决了?
等等,x-k为负怎么办?
...暴力啊!因为C每次都除一个数,所以最多除不过logC次;
枚举到logC判断是否出解就可以了,也顺便把之前x=0的特判统一了;
时间复杂度O(logC+√C/P);
代码:
//代码是JDFZ的代码,多了关于C==1的特判;
#include<math.h> #include<stdio.h> #include<string.h> #include<algorithm> #define N 140142 using namespace std; typedef long long ll; struct Hash_Set { ll head[N], next[N], X[N], val[N], tot; void clear() { memset(head, 0, sizeof(head)); memset(next, 0, sizeof(next)); memset(val, -1, sizeof(val)); memset(X, 0, sizeof(X)); tot = 0; } ll& operator [](ll x) { ll index = x%N; for (ll i = head[index]; i; i = next[i]) { if (X[i] == x) return val[i]; } next[++tot] = head[index]; head[index] = tot; X[tot] = x; return val[tot]; } }hash; ll pow(ll x, ll y, ll mod) { ll ret = 1; while (y) { if (y & 1) ret = ret*x%mod; x = x*x%mod; y >>= 1; } return ret; } ll gcd(ll a, ll b) { ll t = a%b; while (t) { a = b, b = t; t = a%b; } return b; } 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 t, ll mod) { ll x, y; exgcd(t, mod, x, y); return (x%mod + mod) % mod; } ll BSGS(ll A, ll B, ll C) { hash.clear(); ll bk = ceil(sqrt(C)), i, j, k, D, temp; for (i = 0, D = 1; i < bk; i++, D = D*A%C) { if (hash[D] == -1) hash[D] = i; } temp = inv(D, C); for (i = 0, k = B; i <= bk; i++, k = k*temp%C) { if (hash[k] != -1) return i*bk + hash[k]; } return -1; } ll EXBSGS(ll A, ll B, ll C) { if(C==1) { if(!B) return 0; else return -1; } ll lg = ceil(log(C*1.0) / log(2)), i, k, mod; for (i = 0, k = 1; i <= lg; i++, k = k*A%C) { if (k == B) return i; } i = 0, mod = C; while ((k = gcd(A, mod)) != 1) { if (B%k) return -1; B /= k, mod /= k; i++; } ll ret = BSGS(A, B*inv(pow(A, i, mod)*inv(C / mod, mod) % mod, mod) % mod, mod); if (ret != -1) return ret + i; else return -1; } int main() { ll c, T, A, B, C, ans; scanf("%lld", &T); for (c = 1; c <= T; c++) { scanf("%lld%lld%lld", &A, &C, &B); ans = EXBSGS(A, B, C); printf("%lld\n", ans); } return 0; }
时间: 2024-11-05 13:38:03