xgzc— math 专题训练(二)

本文介绍费马小定理、欧拉定理及其扩展,并详细讲解了BSGS算法及其扩展版本EXBSGS算法的具体实现过程,用于解决离散对数问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

费马小定理&欧拉定理

费马小定理:
如果\(p\)是一个质数,而整数\(a\)不是\(p\)的倍数,\(a^{p-1}\equiv1\pmod p\)
欧拉定理:
\(a\)\(n\)互质时,\(a^b \equiv a^{b\%\phi(n)} \pmod n\)
扩展欧拉定理:

\[ a^b \equiv \begin{cases} a^b\pmod n (b<\phi(n))\\ a^{b\%\phi(n)+\phi(n)\pmod n (b\ge\phi(n))}\\ \end{cases} \]

BSGS

求方程\(a^x\equiv b\pmod p\)(\(a\)\(p\)互质)的解
\(m=\lceil \sqrt p\rceil\),设\(x = m*i-j\)
那么易知,\((a^m)^i\equiv b*a^j\pmod p\)
我们可以把右边的全部丢到\(map\)里,然后枚举左边的,看看\(map\)中有没有


map<int, int> M;
int BSGS(int a, int b, int p) {
    if (b == 1 && a) return 0;
    M.clear(); int m = ceil(sqrt(p));
    LL t = 1;
    for (int i = 0; i < m; i++, t = t * a % p) M[t * b % p] = i;
    for (int i = 1, s = t; i <= m + 1; i++, s = t * s % p) {
        map<int, int> :: iterator it = M.find(s);
        if (it == M.end()) continue;
        return m * i - (it->second);
    }
    return -1;
}
int main() {
    int a, b, p;
    while (scanf("%d%d%d", &p, &a, &b) != EOF) {
        int ans = BSGS(a, b, p);
        if (ans == -1) puts("no solution");
        else printf("%d\n", ans);   
    }
    return 0;
}

EXBSGS

\(a\)\(p\)不互质时,就不能除过去。
考虑,\(a^x=p*z+b\)
我们取\(d = gcd(a,p)\)
如果\(b\)不是\(d\)的倍数显然无解
然后整体除\(d\)得到\(\frac{a}{d}a^{x-1}=\frac{p}{d}*z+\frac{b}{d}\)
显然可以递归处理。。
记录一下系数
然后最后回带一下即可。

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int Mod = 1e5 + 7;
int gcd(int x, int y) {
    return !y ? x : gcd(y, x % y);
}
struct Hash {
    struct node {
        int a, b, nxt;
    } A[1000010];
    int lst[Mod], tot;
    void clear() { memset(lst, 0, sizeof(lst)); tot = 0; }
    void add(int a, int b, int S) {
        A[++tot] = (node) {a, b, lst[S]};
        lst[S] = tot;
    }
    void insert(int a, int b) { add(a, b, a % Mod); }
    int find(int x) {
        for (int i = lst[x % Mod]; i; i = A[i].nxt)
            if (A[i].a == x) return A[i].b;
        return -1;
    }
} M;
int exBSGS(int a, int b, int p) {
    if (b == 1 && a) return 0;
    int d, k = 0, s = 1;
    while ((d = gcd(a, p)) > 1) {
        if (b % d) { return -1; }
        b /= d; p /= d; k++; s = 1ll * s * a / d % p;
        if (s == b) { return k; }
    }
    M.clear(); int m = ceil(sqrt(p));
    LL t = 1;
    for (int i = 0; i < m; i++, t = t * a % p) M.insert(t * b % p, i);
    s = t * s % p;
    for (int i = 1; i <= m + 1; i++, s = t * s % p) {
        int it = M.find(s); if (it == -1) continue;
        return m * i - it + k;
    }
    return -1;
}
int main() {
    int a, b, p;
    while (scanf("%d%d%d", &a, &p, &b) != EOF) {
        if (!a && !b && !p) return 0;
        int ans = exBSGS(a, b, p);
        if (ans == -1) puts("No Solution");
        else printf("%d\n", ans);
    }
    return 0;   
}

exLucas

二次剩余(Cipolla)

转载于:https://www.cnblogs.com/zzy2005/p/11523672.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值