zoukankan      html  css  js  c++  java
  • 浅谈BSGS(大步小步)及其扩展

    用途:

    一般用来求(a^xequiv b\,\,(mod\,p))的最小正整数解,其中gcd(a,p)=1

    (u=lceil sqrt(p) ceil),则式子可以转化为(a^{iu-j}equiv b\,\,(mod\,p)),其中(iin[1,u],jin[0,u))

    于是(a^{iu}equiv a^jb\,\,(mod\,p)),我们就可以枚举j,存到map中,再枚举i判重就行了

    不过当存在不同的j使(a^jb\,mod\,p)相同时,我们记录较大的(因为j越大答案越小嘛)

    简易原理:

    费马小定理:若gcd(x,p)=1,则有(\x^{p-1}equiv1\,\,(mod\,p)),得到(x^pequiv x\,\,(mod\,p))

    所以当指数不小于p时,mod p的值会形成循环

    Code:

    板子题:luogu P4028 New Product

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    map<int,int> mp;
    int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    int quickpow(int a,int b,int p){
    	int re=1;
    	while(b){if(b&1) re=1ll*re*a%p;a=1ll*a*a%p;b>>=1;}
    	return re;
    }
    void solve(){
    	int p=read(),a=read(),b=read();
    	if(a%p==0){puts("Couldn't Produce!");return ;}
    	if(b==1){puts("0");return ;}
    	int u=sqrt(p)+1,v=b;mp.clear();
    	for(int i=0;i<u;i++)
            mp[v]=i,v=1ll*v*a%p;
        int w=quickpow(a,u,p);v=1;
        for(int i=1;i<=u;i++){v=1ll*v*w%p;
            if(mp.count(v)){
    			printf("%d
    ",i*u-mp[v]);
    			return ;
    		}
        }puts("Couldn't Produce!");
    }
    int main(){
    	int T=read();
    	while(T--) solve();
    	return 0;
    }
    

    扩展:

    可以看到BSGS是有着局限性的,即必须满足gcd(a,p)=1

    那么当gcd(a,p)!=1时呢?我们设(d=gcd(a,p))

    Step1:

    ​ 我们首先判断(b)是否满足(d|b),若不满足,由裴蜀定理可知无解

    Step2:

    ​ 式子转化为:

    [a^{x-k}frac{a^k}{Pi_{i=1}^kd_i}equiv frac{b}{Pi_{i=1}^kd_i}\,\,(mod\,\,frac{p}{Pi_{i=1}^kd_i}) ]

    ​ 令(c=frac{a^k}{Pi_{i=1}^kd_i},b'=frac{b}{Pi_{i=1}^kd_i},p‘=frac{p}{Pi_{i=1}^kd_i}),若(c=b'),则直接输出(k)

    Step3:

    ​ 令(d=gcd(a,p')),若(d e 1),则返回step1,不过b变成了b'

    全部完成后,我们得到式子:(a^{x-k}cequiv b'\,\,(mod\,\,p')),此时满足(gcd(a,p')=1)

    那么我们便可以直接BSGS了

    Code:

    板子题:luogu P4195 exBSGS

    #include<bits/stdc++.h>
    #include<unordered_map>
    #define ll long long
    using namespace std;
    unordered_map<int,int> mp;
    inline int read(){
        int x=0,f=1;char ch=getchar();
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
        return x*f;
    }
    inline int gcd(int x,int y){
        if(y>x) swap(x,y);
        while(y){swap(x,y);y=y%x;}
        return x;
    }
    inline int quickpow(int a,int b,int p){
        int re=1;
        while(b){if(b&1) re=1ll*re*a%p;a=1ll*a*a%p;b>>=1;}
        return re;
    }
    inline void solve(int a,int p,int b){
        if(p==1){puts("0");return ;}
        if(b==1){puts("0");return ;}
        int d=gcd(a,p),flag=0,k=0,c=1;
        while(d^1){
            if(b%d){
                puts("No Solution");
                flag=1;break;
            }p/=d,b/=d,++k;
            c=1ll*c*(a/d)%p;
            if(b==c){
                printf("%d
    ",k);
                flag=1;break;
            }d=gcd(a,p);
        }if(flag) return ;
        mp.clear();
        int u=sqrt(p)+1,v=b;
        for(int i=0;i<u;i++)
            mp[v]=i,v=1ll*v*a%p;
        v=c,c=quickpow(a,u,p);
        for(int i=1;i<=u;i++){
            v=1ll*v*c%p;
            if(mp.count(v)){
                printf("%d
    ",i*u-mp[v]+k);
                return ;
            }
        }puts("No Solution");
    }
    int main(){
        while(1){
            int a=read(),p=read(),b=read();
            if(a==0&&b==0&&p==0) return 0;
            a%=p;b%=p;solve(a,p,b);
        }
    }
    

    话说为什么unordered_map比map快这么多啊,不过有时候编译会出锅...

  • 相关阅读:
    第一节:SpringMVC概述
    SpringMVC【目录】
    Windows 系统快速查看文件MD5
    (error) ERR wrong number of arguments for 'hmset' command
    hive使用遇到的问题 cannot recognize input
    Overleaf支持的部分中文字体预览
    Understanding and Improving Fast Adversarial Training
    Django2实战示例 第十三章 上线
    Django2实战示例 第十二章 创建API
    Django2实战示例 第十一章 渲染和缓存课程内容
  • 原文地址:https://www.cnblogs.com/NLDQY/p/10877282.html
Copyright © 2011-2022 走看看