高次同余方程 $BSGS$

第一篇\(Blog\)...

还是决定把\(luogu\)上的那篇搬过来了。



BSGS,又名北上广深

它可以用来求\(a^x \equiv b (mod \ n)\)这个同余方程的一个解,其中\(a,n\)互质。

欧拉定理告诉我们,这里\(a^{\varphi(n)} \equiv 1 (mod \ n)\)

由于\(a^0 \equiv 1 (mod \ n)\),所以这里\(x\)到\(\varphi(n)\)后\(a^x \ mod \ n\)就开始循环了。

所以我们最坏情况就是\(n\)为素数时,从\(0\)到\(n-1\)枚举\(x\)就行了。

这样我们就得到了一个\(O(n)\)复杂度的优秀算法。

然而\(n < 2^{31}\)......

我们考虑让\(x = im - j(0 \le j \le m)\),即把\(0...n-1\)这\(n\)个数按每块大小为\(m\)分块。

就有

\[
a^{im - j} \equiv b (mod \ n)
\]

两边同时乘\(a^j\)得

\[
a^{im} \equiv ba^j (mod \ n)
\]

对于等式右边,总共只会有\(m+1\)种不同的\(j\),我们把\(ba^0,ba^1,...,ba^m\)全塞到一个\(map\)里,\(i\)也只会有\(\lceil \frac{n}{m} \rceil\)种取值,直接暴力。

最后复杂度为\(O(m + \lceil\frac{n}{m} \rceil)\)

取\(m = \lceil \sqrt{n} \rceil\),就可以做到\(O(\sqrt{n})\)

当然,用\(map\)的话还要乘上一个\(log\)。

其实分块的时候\(j\)取到\(m\)可能会导致有些\(x\)被考虑到两次,但并不影响,而且边界还不怎么需要处理。

贴一下Luogu P3846(板子题)的代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int fpow(int a, int b, int c){
    int ret = 1;
    for (a %= c; b; b>>=1, a = 1ll*a*a % c) if (b&1) ret = 1ll * ret * a % c;
    return ret;
}

int BSGS(int a, int b, int n, int &ret) {
    int m = ceil(sqrt(n));
    map<int,int> h;
    for (int i = 0, tmp = b%n; i <= m; i++, tmp = 1ll*tmp*a%n)
        h[tmp] = i;
    a = fpow(a, m, n);
    for (int tmp = a, i = 1; i <= m; i++, tmp = 1ll*tmp*a%n)
        if (h.count(tmp)) { ret = 1ll*i*m - h[tmp]; return 1; }
    return 0;
}

int main(){
    int a, b, n, flg, ans; scanf("%d%d%d", &n, &a, &b);
    flg = BSGS(a, b, n, ans);
    if (!flg) puts("no solution"); else printf("%d\n", ans);
    return 0;
}


还有比较毒瘤的就是如果\(a \equiv 0 (mod \ n)\)的时候,需要特判\(b \not\equiv 0 (mod \ n)\)

因为如果\(a\)是\(n\)的倍数,那怎么乘都是\(0\)...

所以板子在这里:

int BSGS(int a, int b, int n, int &ret) {
    a %= n, b %= n;
    if (a == 0) { if (b == 0) { ret = 0; return 1; } else return 0; }
    int m = ceil(sqrt(n)); map<int,int> h;
    for (int tmp = b%n, i = 0; i <= m; i++, tmp = 1ll*tmp*a % n) h[tmp] = i;
    a = fpow(a, m, n);
    for (int tmp = a%n, i = 1; i <= m; i++, tmp = 1ll*tmp*a % n)
        if (h.count(tmp)) { ret = 1ll*i*m - h[tmp]; return 1; }
    return 0;
}


\(ExBSGS\)的话。。。改天学吧 感觉也没什么用

原文地址:https://www.cnblogs.com/wxq1229/p/12207157.html

时间: 2024-12-22 17:47:49

高次同余方程 $BSGS$的相关文章

HDU 5895 矩阵快速幂+高次幂取模

HDU 5895 Mathematician QSC 题意:已知f(n)=2*f(n-1)+f(n-2), g(n)=∑f(i)²(0<=i<=n), 给出n,x,y,s, 求x^(g(n*y))%(s+1); 思路:OEIS查到了g(n)=f(n)*f(n+1)/2, f(n)可以用矩阵快速幂求得, 有一个定理可以用于高次幂取模 x^n %k=x^(n%phi(k)+phi(k)) %k, 此处phi(x)为欧拉函数,但是在对幂次取模时存在一个除2, 又因为(a/b)%k=(a%bk)/b,

数论之高次同余方程(Baby Step Giant Step + 拓展BSGS)

什么叫高次同余方程?说白了就是解决这样一个问题: A^x=B(mod C),求最小的x值. baby step giant step算法 题目条件:C是素数(事实上,A与C互质就可以.为什么?在BSGS算法中是要求a^m在%c条件下的逆元的,如果a.c不互质根本就没有逆元.) 如果x有解,那么0<=x<C,为什么? 我们可以回忆一下欧拉定理: 对于c是素数的情况,φ(c)=c-1 那么既然我们知道a^0=1,a^φ(c)=1(在%c的条件下).那么0~φ(c)必定是一个循环节(不一定是最小的)

BSGS

求解a^x=b(mod p),p为质数时,直接bsgs就可以了. 将x写作km-j,m=sprt(p)时复杂度最优,a^(km)=ba^j(mod p),我们预先求出a^j(j=0~m-1)存入map,然后穷举k=1~p/m,如果map中有值,返回km-cnt[]就可以了. bzoj4128 Matrix 题目大意:a^x=b(mod p),a.b为矩阵. 思路:bsgs直接求就可以了,因为不需要求逆,所以方便许多.(注意map要重定义比较符号) #include<iostream> #inc

高次同余方程模板BabyStep-GiantStep

/************************************* ---高次同余方程模板BabyStep-GiantStep--- 输入:对于方程A^x=B(mod C),调用BabyStep(A,B,C),(0<=A,B,C<=10^9) 输出:无解放回-1,有解放回最小非负整数x 复杂度:O(C^0.5),只与C有关,与A,B的大小无关 ************************************/ typedef long long ll; #define HAS

machine learning in coding(python):拼接原始数据;生成高次特征

拼接原始数据: train_data = pd.read_csv('train.csv') test_data = pd.read_csv('test.csv') all_data = np.vstack((train_data.ix[:,1:-1], test_data.ix[:,1:-1])) numpy下的合并数组vstack和hstack函数: >>> a = np.ones((2,2)) >>> b = np.eye(2) >>> print

扩展欧几里德算法—求解不定方程,线性同余方程

#include<stdio.h> int extended_gcd(int a,int b,int &x,int &y) { int r,t; if(!b) { x = 1; y = 0; return a; } r = extended_gcd(b,a%b,x,y); t = x; x = y; y = t-a/b*y; return r; } int main() { int a,b,x,y,z; scanf("%d%d",&a,&b)

POJ2417 Discrete Logging【高次同余方程】

题目链接: http://poj.org/problem?id=2417 题目大意: 已知整数P.B.N满足公式B^i = N(mod P),求i的值是多少. 思路: 典型的解高次同余方程A^x = B(mod C),直接套模板解决.注意输入顺序:C A B AC代码: #include<iostream> #include<algorithm> #include<cstdio> #include<cstring> #include<cmath>

[poj 2417]Discrete Logging 数论 BSGS

Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 3516   Accepted: 1651 Description Given a prime P, 2 <= P < 231, an integer B, 2 <= B < P, and an integer N, 1 <= N < P, compute the discrete logarithm of N, base B, modulo P.

洛谷P1082 同余方程

题目描述 求关于 x 的同余方程 ax ≡ 1 (mod b)的最小正整数解. 输入输出格式 输入格式: 输入只有一行,包含两个正整数 a, b,用一个空格隔开. 输出格式: 输出只有一行,包含一个正整数 x0,即最小正整数解.输入数据保证一定有解. 输入输出样例 输入样例#1: 3 10 输出样例#1: 7 说明 [数据范围] 对于 40%的数据,2 ≤b≤ 1,000: 对于 60%的数据,2 ≤b≤ 50,000,000: 对于 100%的数据,2 ≤a, b≤ 2,000,000,000