zoukankan      html  css  js  c++  java
  • 『笔记』BSGS

    写在前面

    开始之前先来两首 (music)

    BSGS

    简介

    BSGS(baby-step giant-step),大步小步算法。

    又被称为拔山盖世算法,又被称为北上广深算法。。。。

    作用

    求解满足

    [a^x equiv b pmod p ]

    的最小自然数 (x)

    其中 (a perp p) ,方程的解 (x) 满足 $ 0 leq x < p$ 且数据范围较大,无法直接枚举在 (O(p)) 时间内通过。

    [x=A left lceil sqrt{p} ight ceil-B ]

    其中

    [0 leq A,B leq left lceil sqrt{p} ight ceil ]

    则有

    [a^{left lceil sqrt{p} ight ceil-B} equiv b pmod p ]

    由费马小定理得

    [a^{left lceil sqrt{p} ight ceil} equiv b cdot a^B pmod p ]

    我们已知 (a,b) 的取值,所以直接枚举 (B),计算 (b cdot a^B) ,将其插入 (hash) 表,然后计算 (a^{Aleft lceil sqrt{p} ight ceil}),枚举所有 (A) 的值,看 (hash) 表中是否存在对应的 (b cdot a^B),即可得到所有的解 (x)

    由于 (A,B) 均小于 (leq left lceil sqrt{p} ight ceil) 所以总时间复杂度为 (O(sqrt{p})),若使用 (map) 则多一个 (log)

    例题

    T1

    计算

    [a^x equiv b pmod p ]

    的最小非负整数解,无解时返回 (-1)

    int BSGS(int a, int b, int p)
    {
    	map<int, int> h;
        h.clear();
    	b %= p;
    	int t = (int)sqrt(p) + 1;
    	for (int i = 1; i <= i; i++)
    	{
    		int tmp = (long long)b * Qpow(a, i, p) % p;
    		h[tmp] = i;
    	}
    	a = Qpow(a, t, p);
    	if (!a)
    		return !b ? 1 : -1;
    	for (int i = 0; i <= t; i++)
    	{
    		int tmp = Qpow(a, i, p);
    		if (h.find(tmp) == h.end())
    			return -1;
    		else if (i * t - h[tmp] >= 0)
    			return i * t - h[tmp];
    	}
    	return -1;
    }
    

    拓展 BSGS

    简介

    朴素的 (BSGS) 只有当 (p) 为质数是才可保证正确性,但是 (OI) 比赛中很多时候善良有爱的出题人并不想给出质数,那 (BSGS) 是否依旧可行呢?

    自然,我们可以通过各种手段,使得 (a perp p)

    前置芝士

    (a equiv b(mod m))(d)(a, b)(m) 的任一正公因数,则有

    [cfrac{a}{d} equiv cfrac{b}{d}left(mod cfrac{m}{d} ight) ]

    (a equiv b(mod m), d mid m, d>0), 则 (a equiv b(mod d))

    (a equiv b(mod m)), 则 $a k equiv b k(mod m) $。

    思路

    求解满足

    [a^x equiv b pmod p ]

    的最小自然数 (x)

    其中 (p) 不是质数。

    (d=gcd(a,p))

    (d mid b)(b=1)(x=0) 。否则,由裴蜀定理得,原方程无解。

    不妨假设 (d mid b),将原方程同时除以 (d_1)

    [cfrac{a}{d_{1}} cdot a^{x-1} equiv cfrac{b}{d_{1}} pmod{cfrac{p}{d_{1}}} ]

    此时对 (a,p) 再次进行判断,若 (a)(cfrac{p}{d_1}) 仍旧不互质,那么再除。

    (d_2=gcd(a,cfrac{p}{d_1})),如果,(d mid b_2) 则原方程出现无解情况。否则对原方程同时除以 (d_2),得

    [cfrac{a^{2}}{d_{1} d_{2}} cdot a^{x-2} equiv cfrac{b}{d_{1} d_{2}} pmod{cfrac{p}{d_{1} d_{2}}} ]

    同样执行上述判读和除法操作,直到 (d=1)

    此时有

    [a^{x-k} cfrac{a^k}{prod limits_{i=1}^{k}d_i} equiv cfrac{b}{prod limits_{i=1}^{k}d_i}pmod{cfrac{p}{prodlimits_{i=1}^{k}d_i}} ]

    [egin{aligned} &P=frac{p}{prod limits_{i=1}^{p} d_{i}},\ &B=frac{b}{prod limits_{i=1}^{k} d_{i}},\ &C=frac{a^{k}}{prod limits_{i=1}^{k} d_{i}},\ &X=x-k end{aligned} ]

    则有

    [A^{X} C equiv B pmod{P} ]

    此时的 (A) 是与 (P) 互质的,便可以用朴素的 (BSGS) 求解了。

    /*
    
    Name: P4195 【模板】扩展BSGS
    
    Solution: 扩展BSGS
       
    
    By Frather_
    
    */
    #include <iostream>
    #include <map>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #define int long long
    #define InF 0x3f3f3f3f
    #define kMax 10e5
    #define kMin -10e5
    #define kMod 998244353
    using namespace std;
    /*==================================================快读*/
    inline int read()
    {
        int X = 0, F = 1;
        char CH = getchar();
        while (CH < '0' || CH > '9')
        {
            if (CH == '-')
                F = -1;
            CH = getchar();
        }
        while (CH >= '0' && CH <= '9')
        {
            X = (X << 3) + (X << 1) + (CH ^ 48);
            CH = getchar();
        }
        return X * F;
    }
    /*===============================================定义变量*/
    int a, p, b; //a^x=b (mod p)
    /*=============================================自定义函数*/
    int gcd(int a, int b)
    {
        return b ? gcd(b, a % b) : a;
    }
    
    int Qpow(int a, int p, int kmod)
    {
        int res = 1;
        while (p)
        {
            if (p & 1)
                res = res * a % kmod;
            a = a * a % kmod;
            p >>= 1;
        }
        return res;
    }
    
    // int BSGS(int a, int b, int p, int g)
    // {
    //     map<int, int> hs;
    //     hs.clear();
    //     int t = (int)sqrt(p) + 1;
    //     for (int i = 0; i < t; i++)
    //     {
    //         int v = 1ll * b * Qpow(a, i, p) % p;
    //         hs[v] = i;
    //     }
    //     a = Qpow(a, t, p);
    //     if (!a)
    //         return !b ? 1 : -1;
    //     for (int i = 0; i <= t; i++)
    //     {
    //         int v = Qpow(a, i, p);
    //         // if (hs.find(v) != hs.end())
    //         //     return -1;
    //         // if (hs[v] >= 0 && i * t - hs[v] >= 0)
    //         //     return i * t - hs[v];
    //         int j = hs.find(v) == hs.end() ? -1 : hs[v];
    //         if (j >= 0 && i * t - j >= 0)
    //             return i * t - j;
    //     }
    //     return -1;
    // }
    
    int exgcd(int &x, int &y, int a, int b)
    {
        if (!b)
        {
            x = 1;
            y = 0;
            return a;
        }
        int t = exgcd(y, x, b, a % b);
        y -= x * (a / b);
        return t;
    }
    
    int BSGS(int a, int b, int p, int g)
    {
        map<int, int> hs;
        hs.clear();
        int t = ceil(sqrt(p));
        int x, y;
        exgcd(x, y, g, p);
        b = (b * x % p + p) % p;
        int q = Qpow(a, t, p);
        exgcd(x, y, q, p);
        q = (x * p + p) % p;
        for (int i = 1, j = 0; j <= t; j++, i = i * a % p)
            if (!hs.count(i))
                hs[i] = j;
        for (int i = b, j = 0; j <= t; j++, i = i * q % p)
            if (hs[i])
                return j * t + hs[i];
        return -1;
    }
    int exBSGS(int a, int b, int p)
    {
        int res = 1;
        int k=0, g=1;
        if (b == 1)
            return 0;
        while ((g = gcd(a, p)) > 1)
        {
            if (b % g)
                return -1;
            k++;
            b /= g;
            p /= g;
            res = res * (a / g) % p;
            if (res == b)
                return k;
        }
        return (g = BSGS(a, b, p, res)) == -1 ? -1 : g + k;
    }
    /*=================================================主函数*/
    signed main()
    {
        while (true)
        {
            a = read();
            p = read();
            b = read();
            if (!a && !p && !b)
                return 0;
            a %= p;
            b %= p;
            int ans = exBSGS(a, b, p);
            if (ans < 0)
                printf("No Solution
    ");
            else
                printf("%d
    ", ans);
        }
        return 0;
    }
    

    最后

    掌握的不是很好哇,如果有错误欢迎向作者提出,蟹蟹!

  • 相关阅读:
    JavaScript---动态加载script和style样式
    百度地图API----搜索地址,获取该点的位置坐标并转换成WebMercator
    ArcGIS api for JavaScript 3.27 FindTask查询功能
    Dojo.declare使用方法详解
    ArcGIS Desktop中为图像设置成不显示背景色
    网页导航条定位
    css3+JS实现幻灯片轮播图
    简单json---转树形json
    js中回调函数写法
    pom.xml文件报MavenArchiver错误 org.apache.maven.archiver.MavenArchiver.getManifest(org.apache.maven.project.MavenProject, org.apache.maven.archiver.MavenArchiveConfiguration)
  • 原文地址:https://www.cnblogs.com/Frather/p/14731630.html
Copyright © 2011-2022 走看看