BSGS

 BSGS算法 名拔山盖世算法,又称北上广深算法。

  如果理解了模线性方程A * x  B (mod C)   , BSGS 算法更好理解。

求解A^x ≡ B mod N (N不一定是质数)的最小非负正整数解

 

先放几个同余定理的相关性质:

 

费马引理:a^{p-1} \equiv 1 (mod p)  

 

 

一、判断如果B==1,那么x=0,算法结束

      如果B=1,就是A^{x} % N \equiv 1 ,可得x=0,因为N不可能为1,且任何数的0次幂都是1,所以算法结束。

二、若gcd(A,N)不能整除 B,则 无解,算法结束

    可以证明: d =gcd(A,N), 有 d  | A (代表gcdd是A的因子), d | N, 即有A=a* d,N=n-d;

代入原式即可得 : (a* d)^{x} - (n * d) *y = B ,整理即可得:d *( a* (a* d)^{x-1}- n*y)= B

很显然 d | B; 所以,若gcd(A,N)不能整除 B,则 无解,算法结束。

三、若gcd(A,N)!=1,令d=gcd(A,N),若d不能整除B,则无解,算法结束。

    假设d | B ,  利用剩余定理的相关性质有:        A^{x}\equivB (mod N)    ;

                                                  A^{x-1} * \frac{A}{d}  \equiv \frac{B}{d} (mod \frac{N}{d});     

四、持续步骤三,直至 gcd(A,\frac{N}{\prod_{i-1}^{k}* di })=1

           有    A^{x-k} * \frac{A^{​{k}}}{\prod_{i-1}^{k}* di }  \equiv \frac{B}{\prod_{i-1}^{k}* di } (mod   \frac{N}{\prod_{i-1}^{k}* di } )

五、枚举 0<x<k,若有解,输出x,算法结束

六、对于x>=k,

       这就是经典的BSGS算法,方法如下: 
      令x=i*m− j, m =\left \lceil \sqrt{ p } \right \rceil  ,(向上取整) 则 A^{i*m-j} ≡ b(mod p)

      费马引理:a^{p-1} \equiv 1 (mod p)    并有a^{k (mod (p-1))}= a^{k} mod p

      证明如下:

 


      移项,得(am)i≡baj(modp)(am)i≡baj(modp) 
      首先,从0−m0−m枚举jj,将得到的bajbaj的值存入hash表; 
      然后,从1−m1−m枚举ii,计算(am)i(am)i,查表,如果有值与之相等,则当时得到的im−jim−j是最小值。

#include<map>
#include<cmath>
#include<cstdio>
#include<iostream> 
#include<algorithm> 
 
using namespace std;

typedef long long LL;
 
map<int,int>mp;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}
 
int get_gcd(int a,int b) { return !b ? a : get_gcd(b,a%b); }
 
int Pow(int a,int b,int mod)
{
    int res=1;
    for(;b;a=1LL*a*a%mod,b>>=1)
        if(b&1) res=1LL*res*a%mod;
    return res;
}   
 
int ex_BSGS(int A,int B,int C)
{
    if(B==1) return 0;
    int k=0,tmp=1,d;
    while(1)
    {
        d=get_gcd(A,C);
        if(d==1) break;
        if(B%d) return -1;
        B/=d; C/=d;
        tmp=1LL*tmp*(A/d)%C;
        k++;
        if(tmp==B) return k;
    }
    mp.clear();
    int mul=B;
    mp[B]=0;
    int m=ceil(sqrt(1.0*C));
    for(int j=1;j<=m;++j) 
    {
        mul=1LL*mul*A%C;
        mp[mul]=j;
    }
    int am=Pow(A,m,C);
    mul=tmp;
    for(int j=1;j<=m;++j)
    {
        mul=1LL*mul*am%C;
        if(mp.count(mul)) return j*m-mp[mul]+k;
    }
    return -1;
}
 
int main()
{
    int A,C,B;
    int ans;
    while(1)
    {
        read(A); read(B); read(C); 
        if(!A) return 0;
        ans=ex_BSGS(A,B,C);
        if(ans==-1) puts("No Solution");
        else cout<<ans<<'\n';
    }
}

A=,B=,P=

A,P 互素 ,

直接用BSGS 求    * A ^ x ≡ B mod P

所得结果再+k即可

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值