我们研究一些小问题
先研究对于a^L mod c = b(已知a,b,c, c为质数,求最小的L)的情况。
那么对于L < C的情况:
设m = [sqrt(c)],L = k*m + j;
则(a^(k*m))*(a^j) mod c = b;
baby step:
我们可以知道j < m
我们预处理出a^0 ~ a^(m-1) % c,并且将他们堆入Hash中。(O(m))
giant step:
我们设a^(-m) = p
则(a^j) mod c = b * (p^k) mod c;
我们枚举k.
若b*(p^k) mod c存在于Hash表当中,那代表我们已经找到答案了,可以直接退出。
O(m)
总体复杂度O(m)
练习题:poj2417
接下来是比较难的问题。
给定a,b,c(只有大小限制), 求最小的L使得a^L mod c = b
这题没有了上题的a,b,c互质的情况。
我们可以进行一些消元。
设a^L = k * c + b;
则a * a^(L-1) = k * c + b;
设gcd(a,c) = d
那么(a/d) * a^(L - 1) = k * (c / d) + b/d;
若b mod d <> 0,那么无解。
否则我们记录一个D = π(a/d),d = a除的次数。
那么到最后我们就可以得到D * a^j mod c' = b'
并且此时a,b,c互质了。
我们直接套用上面的普通解法即可。
练习题:spoj_MOD
spoj_Mod
#include
#include
#include
using namespace std;
const int has1 = 57601;
typedef long long LL;
int A[3][has1],N;
int gcd1(int a,int b) {return b ? gcd1(b,a % b) : a;}
int gcd(int a,int b,int &x,int &y)
{
if (!b) {x = 1,y = 0;return a;}
int v = gcd(b,a % b,x,y),t = y;
y = x - (a / b) * y,x = t;
return v;
}
int ex_gcd(int a,int b,int c)
{
int x,y,n = gcd(a,b,x,y);
if (!c % n) return -1;
x = x * LL(c / n) % N;
int k = b / n;
if (k < 0) k = -k;
if (x < 0) x += ((-x) / k + 1) * k;
return x;
}
int hash(int a,int b)
{
int p = a % has1;
while (A[0][p] && A[0][p] != a) p = A[2][p];
if (A[0][p]) return A[1][p];
if (b)
{
A[0][p] = a,A[1][p] = b;
A[2][p] = (p + 1) % has1;
}
return 0;
}
void Work(int a,int b)
{
memset(A,0,sizeof A);
int tmp = 1;
for(int i = 0;i < 31;i ++) if (tmp == b) {printf("%d\n",i);return;} else tmp = tmp * LL(a) % N;
int d = 0,D = 1,k,z,y;
b %= N;
while ((k = gcd1(a,N)) != 1)
{
if (b % k) {printf("No Solution\n");return;}
b /= k,N /= k,d ++,D = D * LL(a) / k % N;
}
int m = sqrt((double)(N));tmp = 1;
for(int i = 1;i <= m;i ++) hash(tmp,i),tmp = tmp * LL(a) % N;
int Nt = tmp;
tmp = 1;
for(int i = 0;i <= m;i ++)
{
int p = ex_gcd(D * LL(tmp) % N,N,b),l;
tmp = tmp * LL(Nt) % N;
if (p == -1 || !(l = hash(p,0))) continue;
{printf("%d\n",i * m + l - 1 + d);return;}
}
printf("No Solution\n");
}
int main()
{
int a,b;
while (scanf("%d %d %d", &a, &N, &b) != EOF && ((a | N) | (b))) Work(a,b);
}