zoukankan      html  css  js  c++  java
  • BSGS学习笔记

    用于求\(A^x \equiv B \pmod{C}\) 高次方程的最小正整数解 \(x\),其中 \(C\) 为素数


    引理1:

    \[a^{i\bmod\varphi(p)} \equiv a^i \pmod p \]

    \(p\)为素数,即 \(a^i\) 在模 \(p\) 的意义下会出现循环节 (注: \(\varphi(p)\) 可能不是最小循环节)

    因为 \(a^{p-1}\equiv 1\pmod p\),则 \(a^{k\times(p-1)} \equiv 1 \pmod p\)

    所以 \(a^{2k\times(p-1)}\times a^{-k*\times(p-1)} \equiv 1 \pmod p\)

    \(a^{2k\times(p-1)}\)\(a^{-k\times (p-1)}\)\(p\) 意义下的逆元

    $ \frac{a{i}}{a{k(p-1)}} \equiv a^{i}\times a^{2k\times (p-1)} \equiv a^{i}\times 1 \equiv a^{i} \pmod p$

    \(a^{i-k(p-1)} \equiv a^{i} \pmod p\)

    又因为 $i \bmod \varphi(p)=i-k\times (p-1) $

    \(p\) 为素数,\(i-k\times (p-1)=i-k\times\varphi(p)\)

    \(a^{i-k\times(p-1)} \equiv a^{i\mod\varphi(p)} \equiv a^{i} \pmod p\)

    QED


    根据引理1我们可知只需要枚举至多 \(\varphi(C)\) 个数就能知道方程的解,若枚举完后发现无解,则整个方程无解

    考虑构造一个 \(m\),使得 \(m=\lceil\sqrt{C}\rceil\)

    \(x=k\times m-q\),原方程转化为 \(A^{k\times m-q} \equiv B \pmod{p}\)

    继而得到 $ A^{k\times m} \equiv B\times A^{q} \pmod{p}$

    到了这一步,我们先考虑枚举 \(B*A^{q}\) 中的 \(q\),至多 \(\sqrt{C}\) 次,然后我们把得到的值存入一个Hash表中

    接着我们开始枚举 $ A^{k\times m}$ 中的 \(m\),则两次枚举出来的式子的两两组合正好可以得到所有 $a \in [1,x] $,若遇到两次枚举出来的值相等,则输出答案,退出循环。

    Code:

    #include<stdio.h>
    #include<math.h>
    #include<map>
    using namespace std;
    #define ll long long
    #define int ll
    #define HASH_MOD 76799777LL
    
    map<int,int> hash;
    
    ll qpow(ll A,ll B,ll C){
        if(B==0) return 1;
        if(B==1) return A;
        ll t=qpow(A,B>>1,C);
        t=t*t%C;
        if(B&1) t=t*A%C;
        return t;
    }
    ll BSGS(ll A,ll B,ll C){
        const int sizes=ceil(sqrt(C));
        ll base=B%C;
        hash[base]=0;
        for(int i=1;i<=sizes;i++){
            base=base*A%C;
            hash[base]=i;
        }
        base=qpow(A,sizes,C);
        ll tmp=1;
        for(ll i=1;i<=sizes;i++){
            tmp=tmp*base%C;
            if(hash[tmp])
                return ((i*sizes-hash[tmp])%C+C)%C;
        }
        return -1;
    }
    ll P,B,N;
    signed main(){
        scanf("%lld%lld%lld",&P,&B,&N);
        if(!(B%P)){
            printf("no solution\n");
            return 0;
        }
        ll ans=BSGS(B,N,P);
        if(ans!=-1) printf("%lld",ans);
        else printf("no solution");
    }
    
  • 相关阅读:
    用UltraISO制作U盘启动盘及设BIOS从U盘启动的方法
    Android 超链接 打开网址
    ActionScript常用正则表达式收集
    Android模拟器安装,使用APK文件
    正则表达式的规则
    WORD的批注
    机械迷城 迷宫全图
    mysql新建用户及授权
    验证IP是否合法
    ThinkPad水货靠谱店
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/10546079.html
Copyright © 2011-2022 走看看