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快这么多啊,不过有时候编译会出锅...

  • 相关阅读:
    解决ftp的pasv模式下iptables设置问题
    linux修改运行中的脚本
    shell脚本——列出质数
    转载:tomcat设置https的两种方式
    Centos缺少ifconfig命令
    转载:MySQL 数据库设计总结
    转载:HTML5视频推流方案
    转载:Linux五种方案快速恢复你的系统
    转载:HT可视化案例
    转载:21种JavaScript设计模式最新记录(含图和示例)
  • 原文地址:https://www.cnblogs.com/NLDQY/p/10877282.html
Copyright © 2011-2022 走看看