现在我来介绍一种算法叫做Baby Step Giant Step。它是用来解决如下方程最小正整数解的
其中
如果
,那么我们可以先取模,即
,所以在这里我们只讨论
的情况。
普通Baby Step Giant Step的步骤是这样的:
(1)首先确定
的下限是0,上限是
,我们令
(2)把
的值存到一个Hash表里面 (3)把
的值一一枚举出来,每枚举一个就在Hash表里面寻找是否有一个值
满足
,如果有则找到答案,否则继续 (4)最终答案就是
的值对应的原来
的幂
普通Baby Step Giant Step的步骤,比较简单,只适用
为素数的情况。如果
为合数呢?
当
为合数时,我们就需要把Baby Step Giant Step扩展一下。在普通Baby Step Giant Step中,由于
是素数,那么
,所以
一定有唯一解的。那么,当
为合数时,我们可以这样处理:
对于方程
,我们拿出若干个
出来与
来消去公共因子,使得
为止,那么此时我们就可以直接通过扩展欧几里得来计算结果了。
题目:http://www.spoj.com/problems/MOD/
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <math.h>
using namespace std;
typedef long long LL;
const int MOD = 99991;
const int N = 100005;
struct Hash
{
bool f;
int id;
int val;
};
Hash hash[N];
void Init()
{
for(int i=0; i<N; i++)
{
hash[i].f = 0;
hash[i].id = -1;
hash[i].val = -1;
}
}
void Insert(int id,LL val)
{
LL t = val % MOD;
while(hash[t].f && hash[t].val != val)
{
t++;
t %= MOD;
}
if(!hash[t].f)
{
hash[t].f = 1;
hash[t].id = id;
hash[t].val = val;
}
}
int Find(LL val)
{
LL t = val % MOD;
while(hash[t].f && hash[t].val != val)
{
t++;
t %= MOD;
}
if(!hash[t].f) return -1;
return hash[t].id;
}
LL gcd(LL a,LL b)
{
return b ? gcd(b,a%b):a;
}
void extend_Euclid(LL a,LL b,LL &x,LL &y)
{
if(b == 0)
{
x = 1;
y = 0;
return;
}
extend_Euclid(b,a%b,x,y);
LL tmp = x;
x = y;
y = tmp - (a / b) * y;
}
LL Baby_Step(LL A,LL B,LL C)
{
LL ret = 1;
for(int i=0; i<=50; i++)
{
if(ret == B) return i;
ret = ret * A % C;
}
LL ans = 1;
LL tmp,cnt = 0;
while((tmp = gcd(A,C)) != 1)
{
if(B % tmp) return -1;
B /= tmp;
C /= tmp;
ans = ans * (A / tmp) % C;
cnt++;
}
LL M = ceil(sqrt(1.0*C));
LL t = 1;
for(int i=0; i<M; i++)
{
Insert(i,t);
t = t * A % C;
}
for(int i=0; i<M; i++)
{
LL x,y;
extend_Euclid(ans,C,x,y);
LL val = x * B % C;
val = (val % C + C) % C;
LL j = Find(val);
if(j != -1) return i * M + j + cnt;
ans = ans * t % C;
}
return -1;
}
int main()
{
LL A,B,C;
while(cin>>A>>C>>B)
{
Init();
if(A + B + C == 0) break;
A %= C; B %= C;
LL ans = Baby_Step(A,B,C);
if(ans == -1)
{
puts("No Solution");
continue;
}
cout<<ans<<endl;
}
return 0;
}