• 与数论的厮守03:大步小步算法


      这是个名字很新奇的算法。它用来求方程axΞb(mod c)的最小非负整数解,其中ac互质。

      先看欧拉定理:aΦ(c)Ξ1(mod c)。所以x肯定在0~Φ(c)-1里面。所以我们可以考虑枚举x。但显然会超时。

      大步小步算法将我们的暴力枚举变得更加优雅了些。它的步骤是:把0~c-1分成m=√Φ(c)块,然后把a0,a1,a2...am mod c存进去。这里有两种思路,一种是hash,另一种是有序数组加二分,差异不大。如果有解,x就可以表示成i*m+j的形式。于是我们枚举i,ai*m+j=(ai)m*ajΞb(mod c),再分别求出(ai)m mod c和aj mod c即可。怎么求呢?(ai)m容易得到,所以我们来看aj mod c。

        1.扩展欧几里得。先求出u=(ai)m,方程就变为ajΞb/u(mod c),然后扩欧即可。

        2.欧拉定理。v=aj mod c=aΦ(c)-i*m*b mod c,因为ac互质,所以v唯一。

      显然第二种更简单。求出v之后,我们再去之前的有序数组或者hash表里面查找最小的j使得aj mod c = v,若找到了答案就为i*m+j,否则无解。

      时间复杂度为O(clogc)。

      下面是UVA10225 Discrete Logging的代码。注:题中的c为素数,2≤a,b≤c-1,2≤c≤2^31-1所求方程为axΞb(mod c)

    #include <algorithm>
    #include <cstdio>
    #include <cmath>
    #define maxn 1000010
    using namespace std;
    
    pair<int, int> re[maxn];
    inline long long find(long long l, long long r, long long x){
        long long mid;
        while(l != r){
            mid = (l + r) >> 1;
            if(re[mid].first < x) l = mid + 1;
            else r = mid;
        }
        return re[l].first == x ? l : -1;
    }
    
    inline long long pow(long long a, long long b, long long c){
        long long ans = 1;
        while(b){
            if(b & 1) ans = (long long) ans * a % c;
            a = (long long) a * a % c;
            b >>= 1;
        }
        return ans;
    }
    
    inline long long solve(long long a, long long b, long long c){
        long long m = (double)(sqrt(c - 1) + 0.5);
        re[0].second = 0, re[0].first = 1;
        for(long long i = 1; i < m; i++)
            re[i].second = i, re[i].first = re[i - 1].first * a % c;
        sort(re, re + m);
        for(long long i = 0; i <= m; i++){
            long long v = (long long)pow(a, c - 1 - i * m, c) * b % c;
            long long j = find(0, m - 1, v);
            if(~j) return (long long)i * m + re[j].second;
        }
        return -1;
    }
    
    int main(){
        long long a, b, c;
        scanf("%lld %lld %lld", &c, &a, &b);
        long long ans = solve(a, b, c);
        if(~ans) printf("%lld\n", ans);
        else puts("no solution");
        return 0;
    }
  • 相关阅读:
    javascript入门教程笔记
    杭电2025
    杭电 2024
    杭电2019
    UEditor编辑器上传图片开发流程
    js操作textarea方法集合
    ueditor编辑器和at.js集成
    js分页算法
    js获取url中的参数
    第7章函数表达式笔记
  • 原文地址:https://www.cnblogs.com/akura/p/10715401.html
Copyright © 2020-2023  润新知