数论之高次同余方程(Baby Step Giant Step + 拓展BSGS)

什么叫高次同余方程?说白了就是解决这样一个问题:

A^x=B(mod C),求最小的x值。

 

baby step giant step算法

题目条件:C是素数(事实上,A与C互质就可以。为什么?在BSGS算法中是要求a^m在%c条件下的逆元的,如果a、c不互质根本就没有逆元。

如果x有解,那么0<=x<C,为什么?

我们可以回忆一下欧拉定理:

对于c是素数的情况,φ(c)=c-1

那么既然我们知道a^0=1,a^φ(c)=1(在%c的条件下)。那么0~φ(c)必定是一个循环节(不一定是最小的)。既然是%c,那么B一定是0到c-1之间的一个数。最坏的条件下,a的φ(c)以内次方%c的余数各不相同,0<=x<C时一定存在一个x满足条件。根据抽屉原理,如果在大于c的x中出现一个x值满足条件,那在它以前一定有一个更小的x值满足条件。

 

BSGS的算法是这样的:

首先取m=sqrt(c)向上取整。(为什么取sqrt(c)?我也不是很懂,是为了算法的效率平衡。)

然后先预处理a的0到m次方。

a^x=b ( %c )
设x=i*m+j;
即: i为x/m,j为x%m。
a^(i*m+j)=b;
b * (a^(-m))^i = a^j ( %c )

先枚举j,把右边存起来(Hash 或者 普通数组,下一步用二分查找)
枚举i,如果左边的数值曾经存储过(b * (a^(-m))^i = a^j),则 x=i*m+j。

 

求a^(-m):(就是a^m的逆元)

有两种方法:

   方法一:根据欧拉定理

 

                设A=a^m,那么A^φ(c)==1(%c)

                A^(φ(c)-1)*A==1(%c)

               到这里已经可以得到A的逆元为A^(φ(c)-1)。

               继续推下去,根据c是素数,φ(c)=c-1

               那么A的逆元就是A^(c-2)

     

   方法二:相当于解a^m*x-C*y=1,根据拓展欧几里得出x就是逆元。

 

BSGS主要就是要注意细节,注意要去重(余数相同时只要取较小的一个)。

 

 

拓展BSGS

 

如果a跟c不互质,那该怎么办?

其实只需要加一小段代码就可以。

首先,我们知道:

A%C=B,那么就是A-C*x=B,如果d=gcd(A,C),且B%d==0,那么(A/d)%(C/d)=B/d是成立的。

那么我们就在A与C仍有不为一的公因数的时候,不断地从a^x中拿出一个a与c约分。过程中如果b%d!=0,那么无解。

LL D=1%C; LL g=0,d; while(  ( d=gcd(A,C)   )  !=1 ) { if(B%d)return -1; B/=d;C/=d; g++;D=D*(A/d)%C; }
View Code

最后我们的方程就变为了k*a^(x-g) == b' (%c')

用BSGS解出x后加上g就是答案。

 

你可能感兴趣的:(数论之高次同余方程(Baby Step Giant Step + 拓展BSGS))