zoukankan      html  css  js  c++  java
  • 离散对数求解学习笔记

    一个经典的算法——BSGS算法

        BSGS全名为Baby-Step-Giant-Step,即大小步法,有人戏称之为北上广深算法。可以快速求解离散对数问题,形如,C是素数。

        BSGS算法使用了一个重要的引理:

    重要的引理

        如果,那么

        证明这个引理需要用到欧拉定理

    欧拉定理

        如果,那么

        证明(十分精彩的证明):

            将小于C且与C互质的数顺序列出:

            令

            那么数列m有如下两个性质:

            1)这些数中的任意两个都不模C同余。

            假设存在两个数使得,则

            ,矛盾。

            因此,这个数有种余数。

            2)这些数模C的余数都和C互质。

            假设其中一个数模C的余数与C有公因子r,则,矛盾。

            因此,这些数模C的余数包含于x。

            由这两个性质可得:

           

            QED.

        使用欧拉定理,得

        QED.

        证明完这个引理,BSGS的步骤就很简单了。只需要考虑的情况,其他情况周期出现。(当然,并不一定是最小正周期)对答案分块,令,则答案x可以写作的形式,即。对于每一个i,至多有一个j对应使等式成立,预处理将对应的j哈希掉,总复杂度

     1 void bsgs(int u, int v) {
     2     if(!u && !v) return 2;
     3     else if(!u) return -1;
     4     int m = ceil(sqrt(mod)); hash.clear();
     5     hash[1] = m; int p = u, q = v, iv = inv(pow(u, m));
     6     for(int i = 1; i < m; i++, p = 1ll * p * u % mod) hash[p] = i;
     7     for(int i = 0; i <= m; i++) {
     8         if(hash[q]) return i * m + hash[q] % m + 1; 9         q = 1ll * q * iv % mod;
    10     }
    11     puts("-1");
    12 } 

    更泛用的算法——扩展BSGS算法

        BSGS非常神奇,但只能解决A和C互质的情况。扩展BSGS基于BSGS算法,但可以解决A和C不互质的情况。

        令,则。若B不是d的倍数且非1则显然无解。

    一个简单的同余性质

       

        原方程可以化为。令,则可递归处理直到A和C互质,使用BSGS算法解决即可。

        需要注意的是,原方程最后被化为了的形式。BSGS只能求解的情况,所以需要枚举0-num-1。

     1 int exbsgs(int a, int b, int p) {
     2     a %= p; b %= p;
     3     if(b == 1) return 0; int cnt = 0; ll t = 1;
     4     if(a == 0) return b > 1 ? -1 : b == 0 && p > 1;
     5     for(int g = gcd(a, p); g != 1; g = gcd(a, p)) {
     6         if(b % g) return -1;
     7         p /= g; b /= g; t = 1ll * t * (1ll * a / g % p) % p;
     8         cnt++; if(b == t) return cnt;
     9     }
    10     hash.clear(); int m = ceil(sqrt(p));
    11     ll u = b; for(int i = 0; i < m; i++, u = 1ll * u * a % p) hash[u] = i;
    12     ll v = t, iv = pow(a, m, p);
    13     for(int i = 0; i <= m; i++) {
    14         v = 1ll * v * iv % p;
    15         if(hash.count(v)) return (i + 1) * m - hash[v] + cnt;
    16     }
    17     return -1;
    18 }
  • 相关阅读:
    运营设计方法论
    使用 typescript ,提升 vue 项目的开发体验(2)
    PAT 1078. 字符串压缩与解压
    PAT 1077. 互评成绩计算
    PAT 1076. Wifi密码
    PAT 1075. 链表元素分类
    PAT 1074. 宇宙无敌加法器
    PAT 1073. 多选题常见计分法
    PAT 1072. 开学寄语
    PAT 1071. 小赌怡情
  • 原文地址:https://www.cnblogs.com/aseer/p/9675610.html
Copyright © 2011-2022 走看看