• BSGS


    前言

    ( ext{BabyStepGiantStep})算法,即大步小步算法

    又名 拔山盖世北上广深 算法

    讲解

    按照惯例,我们先来一波百度百科自学时间

    百度百科竟然没有BSGS,我佛了

    ( ext{BSGS})是用来求解关于(x)的方程,(P)是质数

    [A^x≡Bpmod P ]

    一般是找最小的(x)

    1.普通BSGS

    ((A,P)=1)的情况

    由费马小定理,得(A^{P-1}≡1pmod P)

    (ecause A^0≡1pmod P)

    ( herefore A)的幂存在循环节,且循环节长度为(P-1)

    但其实(P)不为质数也很明显存在循环节

    (1).暴力

    我们直接暴力检验循环节的每一个元素就好了

    时间复杂度为(O(P))

    (2).普通BSGS

    而如果我们采用( ext{BSGS})算法:

    先把(x)写成(im-j)的形式((m)自取)

    原式可化为:

    [A^{im}≡BA^{j}pmod P ]

    对于右边每一个(BA^j),我们将其存进(map)或者哈希表中,然后枚举(i),在其中查找(A^{im})是否出现过

    找到即有解

    明显时间复杂度为(O(max(P/m,m)))

    (m=sqrt{P})时时间复杂度最优

    所以普通的( ext{BSGS})的时间复杂度为(O(sqrt{P}))

    点击查看代码
    void BSGS(int A,int B,int P)
    {
    	if(B == 1) {Put(0,'
    '); return;}
    	int m = ceil(sqrt(P)),now = B % P;
    	for(int i = 0;i < m;++ i) ins(now,i),now = 1ll * now * A % P;
    	int Am = qpow(A,m,P); now = 1;
    	for(int i = 1;i <= m;++ i)
    	{
    		now = 1ll * Am * now % P;
    		int dz = query(now);
    		if(dz != -1)
    		{
    			Put(1ll*i*m - dz,'
    ');
    			return;
    		}
    	}
    	printf("no solution
    ");
    }
    

    2.扩展BSGS

    如果((A,P) eq1)怎么办?

    (d=(A,P)),再将原方程化为:

    [A^x+kP=B(kin Z) ]

    明显(d|B),否则无解

    继续改写方程:

    [frac{A}{d}A^{x-1}+kfrac{P}{d}=frac{B}{d} ]

    这样的话(frac{A}{d})就成为了一个系数

    不断检查((A,frac{P}{d})),直到互质

    此时方程可化为:

    [frac{y^{cnt}}{d}y^{x-cnt}≡frac{B}{d}pmod {frac{P}{d}} ]

    注意此时的(d)是并不是最初的(d),而是做了(cnt)次操作累计起来的(d)

    其中我的代码将(frac{y^{cnt}}{d})定为(a)

    点击查看代码
    void EXBSGS(int A,int B,int P)
    {
    	if(B == 1) {Put(0,'
    '); return;}
    	int a = 1,cnt = 0,d;
    	while(122520)
    	{
    		if((d = gcd(A,P)) == 1) break;
    		if(B % d) {printf("No Solution
    ");return;}
    		P /= d; B /= d; ++cnt; a = 1ll * a * A / d % P;
    		if(B == a) {Put(cnt,'
    ');return;}
    	}
    	int m = ceil(sqrt(P)),now = B;
    	for(int i = 0;i < m;++ i) ins(now,i),now = 1ll * now * A % P;
    	int Am = qpow(A,m,P); now = a;
    	for(int i = 1;i <= m;++ i)
    	{
    		now = 1ll * Am * now % P;
    		int dz = query(now);
    		if(dz != -1)
    		{
    			Put(1ll*i*m - dz + cnt,'
    ');
    			return;
    		}
    	}
    	printf("No Solution
    ");
    }
    

    练习

    普通( ext{BSGS})

    Discrete Logging (洛谷)

    扩展( ext{BSGS})

    Clever Y (POJ)

    代码

    Discrete Logging

    点击查看代码
    //12252024832524
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 10005;
    const int MOD = 122520;
    int head[MOD],tot;
    struct node
    {
    	int val,ID,nxt;
    }hs[46341 + 5];
    
    int qpow(int x,int y,int P)
    {
    	int ret = 1;
    	while(y) {if(y & 1) ret = 1ll * ret * x % P;x = 1ll * x * x % P;y >>= 1;}
    	return ret;
    }
    void ins(int x,int ID)
    {
    	hs[++tot].val = x;
    	x %= MOD;
    	hs[tot].ID = ID;
    	hs[tot].nxt = head[x];
    	head[x] = tot;
    }
    int query(int x)
    {
    	for(int i = head[x % MOD]; i ;i = hs[i].nxt)
    		if(hs[i].val == x) return hs[i].ID;
    	return -1;
    }
    void BSGS(int A,int B,int P)
    {
    	if(B == 1) {Put(0,'
    '); return;}
    	int m = ceil(sqrt(P)),now = B % P;
    	for(int i = 0;i < m;++ i) ins(now,i),now = 1ll * now * A % P;
    	int Am = qpow(A,m,P); now = 1;
    	for(int i = 1;i <= m;++ i)
    	{
    		now = 1ll * Am * now % P;
    		int dz = query(now);
    		if(dz != -1)
    		{
    			Put(1ll*i*m - dz,'
    ');
    			return;
    		}
    	}
    	printf("no solution
    ");
    }
    
    int main()
    
    	int Mod,a;
    	while(~scanf("%d %d",&Mod,&a)) 
    	{
    		memset(head,0,sizeof(head)); tot = 0;
    		BSGS(a,Read(),Mod);
    	}
    	return 0;
    }
    

    Clever Y

    点击查看代码
    void EXBSGS(int A,int B,int P)
    {
    	if(B == 1) {Put(0,'
    '); return;}
    	int a = 1,cnt = 0,d;
    	while(122520)
    	{
    		if((d = gcd(A,P)) == 1) break;
    		if(B % d) {printf("No Solution
    ");return;}
    		P /= d; B /= d; ++cnt; a = 1ll * a * A / d % P;
    		if(B == a) {Put(cnt,'
    ');return;}
    	}
    	int m = ceil(sqrt(P)),now = B;
    	for(int i = 0;i < m;++ i) ins(now,i),now = 1ll * now * A % P;
    	int Am = qpow(A,m,P); now = a;
    	for(int i = 1;i <= m;++ i)
    	{
    		now = 1ll * Am * now % P;
    		int dz = query(now);
    		if(dz != -1)
    		{
    			Put(1ll*i*m - dz + cnt,'
    ');
    			return;
    		}
    	}
    	printf("No Solution
    ");
    }
    
    int main()
    {
    	int A,B,Mod;
    	while(~scanf("%d",&A)) 
    	{
    		Mod = Read(); B = Read();
    		if(!A && !Mod && !B) return 0;
    		memset(head,0,sizeof(head)); tot = 0;
    		EXBSGS(A % Mod,B % Mod,Mod);
    	}
    	return 0;
    }
    
  • 相关阅读:
    4.22课堂
    4.21课堂
    4.20作业
    4.20课堂
    4.17课堂
    4.16课堂
    4.15作业
    4.15反射与内置方法
    4.10绑定与非绑定
    70、django中间件
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/13392259.html
Copyright © 2020-2023  润新知