(扩展)BSGS与高次同余方程

前言:

今天更BSGS算法。俗称大步小步算法(Big-Step G…-Step),又称拔山盖世、北上广深、白色狗屎
 
 

问题:

求解指数同余方程: a x ≡ b ( m o d    p ) a^{x}\equiv b(mod\; p) axb(modp)的最小自然数解。
 
 

BSGS算法:模板题

这个算法只考虑 g c d ( a , p ) = 1 gcd(a,p)=1 gcd(a,p)=1的情况。
 
那么,怎么做呢。
其实做法很简单,就是枚举
 
先来一种暴力枚举
就是枚举 x x x [ 0 , p − 1 ] [0,p-1] [0,p1],然后检验答案是否正确。
知道欧拉定理的应该知道只要枚举到 φ ( p ) − 1 \varphi(p)-1 φ(p)1,但 p p p为质数时欧拉函数仍为 p − 1 p-1 p1
看过阶与原根的应该知道只要枚举到 p p p的阶即可,但算 p p p的阶仍然要暴力去枚举。
所以这里只要一个一个枚举过去便好。
 
但是 o ( p ) o(p) o(p)的暴力枚举配不上这么高大上的名字,所以还有优化的余地。
我们可以考虑折半枚举
怎么折半,就是这个算法的精髓了。
我们令 x = k n + i x=kn+i x=kn+i,其中 n n n为我们设置的一个定值, k k k和i i i i均为变量。
这样原式就变为 a k n + i ≡ b ( m o d    p ) a^{kn+i}\equiv b(mod\;p) akn+ib(modp)
由于 g c d ( a , p ) = 1 gcd(a,p)=1 gcd(a,p)=1,我们可以将 a i a^{i} ai的逆元乘到右边,变成 a k n ≡ b ( a i ) − 1 ( m o d    p ) a^{kn}\equiv b(a^{i})^{-1}(mod\;p) aknb(ai)1(modp)
这样我们可以枚举所有的 i i i,将其对应右边的值存入哈希表(也可用unordered_map)。然后枚举 k k k的过程中,去表中找满足的 i i i,找到后 k n + i kn+i kn+i就是答案。当然因为要找最小的,枚举过程中动点手脚就好了。
那么这个 n n n的设置嘛,利用分块的思想, n n n设为 p \sqrt{p} p 就好了,这样 k k k只用枚举到 p \sqrt{p} p i i i也只用枚举到 p \sqrt{p} p 。总的复杂度为 n \sqrt{n} n

上代码:

#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;

ll fpow(ll a,ll n,ll mod)
{
   
    ll sum=1,base=a%mod;
    while(n!=0)
    {
   
        if(n%2)sum=sum*base%mod;
        base=base*base%mod;
        n/=2;
    }
    return sum;
}

ll ex_gcd(ll a,ll b,ll& x,ll& y)
{
   
    if(b==0)
    {
   
        x=1;y=0;
        return a;
    }
    ll ans=ex_gcd(b,a%b,x,y);
    ll tmp=x;
    x=y;
    y=tmp-a/b*y;
    return ans;
}

ll inv
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值