BSGS算法!

Posted oierglh

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BSGS算法!相关的知识,希望对你有一定的参考价值。

 求解关于x的方程

a^x=z(mod p),其中gcd(a,p)=1.
 
做法的话并不难,但是要搞懂细节还蛮多的。
 
bsgs算法是这样的:x可以写成i*m-j的形式(这里m取值随意,但是取√p上取整时跑的最快)
  a^(im-j)≡z(mod p)
  推得  a^im≡z*(a^j)
那么我们枚举j的值从0--(m-1),将算出的z*(a^j)加入map里面
再枚举i从1-m,将每次算出的a^im的结果去map中匹配
若匹配到,x=i*m-j。
 
细节
1.i的范围从1到m
证明:

a ^ x Ξ b (mod p) 

a ^ (p-1) Ξ 1 (mod p)

若x大于等于p-1

则a^xΞa^(p-1) * a^(x-p+1)Ξa^(x-p+1)

故x小于p-1

又m=√p

故i从1到m

得证

2.为什么bsgs在跳步过程中没有漏解

原因:在枚举i的过程中,看似是跳过了好多情况,但是其实在计算了每一个i之后,都会去map里面找每一个j去对应,相当于是将每一个i所对应的余数(剩余系)都枚举了一遍,即枚举了一遍完整的x的范围(因为x=i*m-j)。

 
洛谷p2485  计算器
bsgs裸题
直接粘代码
 
CODE!
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll t,k,y,z,p;
map<ll,ll>a;
ll fpow(ll a,ll b,ll p)

    ll ret=1;
    while(b)
    
        if(b&1) ret=(ret*a)%p;
        b>>=1;
        a=(a*a)%p;
    
    return ret;

void exgcd(ll a,ll b,ll &gcd,ll &xx,ll &yy)

    if(!b)
    
        xx=1,yy=0;
        gcd=a;
        return;
    
    exgcd(b,a%b,gcd,xx,yy);
    ll tr=xx;
    xx=yy;
    yy=tr-a/b*yy;

int main()

    cin>>t>>k;
    if(k==1) 
    
        while(t--)
        
            scanf("%lld%lld%lld",&y,&z,&p);
            printf("%lld\n",fpow(y,z,p));
        
    
    else if(k==2)
        
            while(t--)
            
                scanf("%lld%lld%lld",&y,&z,&p);
                ll gcd,xx,yy;
                exgcd(y,p,gcd,xx,yy);
                if(z%gcd!=0) printf("Orz, I cannot find x!\n");
                else 
                
                    xx*=z/gcd;
                    xx%=(p/gcd);
                    printf("%lld\n",(xx+(p/gcd))%(p/gcd));
                
            
            
        
        else
        
            while(t--)
            
                scanf("%lld%lld%lld",&y,&z,&p);
                ll m=ceil(sqrt(p));
                if(y%p==0&&z) printf("Orz, I cannot find x!\n");continue;;
                a.clear();
                ll now=z%p,f=fpow(y,m,p);
                a[now]=0;
                for(ll i=1;i<=m;i++)
                
                    now=(now*y)%p;
                    a[now]=i;
                
                now=1;
                ll flag=0;
                for(ll i=1;i<=m;i++)
                
                    now=(now*f)%p;
                    if(a[now])
                    
                        ll ans=(i*m-a[now])%p;
                        printf("%lld\n",(ans+p)%p);
                        flag=1;
                        break;
                    
                
                if(!flag) printf("Orz, I cannot find x!\n");
            
        
    return 0;

ps.不开long long见祖宗可还行

以上是关于BSGS算法!的主要内容,如果未能解决你的问题,请参考以下文章

BSGS算法

BSGS算法初探

BSGS算法及拓展

BSGS算法(大步小步算法)

bsgs(Baby Steps Giant Steps)算法

BSGS算法!