题意:
求解方程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;
}