[SDOI2011][洛谷P2485]计算器(BSGS模板)

题面

https://www.luogu.com.cn/problem/P2485

题解

对于T=1,快速幂即可。
对于T=2,exgcd即可。
重点是T=3,需要使用BSGS算法。

BSGS算法

用来快速求解形如\({a^x}{\equiv}r(mod p)\)的指数同余方程的算法,适用范围是\(\gcd(a,p)=1\)
由欧拉-费马定理可得\(a^{\phi(p)}{\equiv}1(mod p)\)。下设\(0<=x<{\phi(p)}\)
设置“间隔”\(T\),那么x一定可以表示成\(iT-j\)(其中\(1<=j<=T\))的形式。下有

\[a^{iT-j}{\equiv}r{\mod p}\]

\[a^{iT}{\equiv}r*a^j{\mod p}\]
故只要某一个\(a^{iT}(1<=i<={\lceil{{\phi(p)-1}\over{T}}\rceil})\)以及某一个\(r*a^j(1<=j<=T)\)相等,就得到了一个解\(x=iT-j\)

实现时只需要将所有的\(r*a^j\)预处理好放入Hash表内,在计算\(a^{iT}\)的时候同步查询就可以了。

计算\(r*a^j\)的时间复杂度为\(O(T)\),计算\(a^{iT}\)的时间复杂度是\(O({{\phi(p)}\over{T}})\),取\(T=\sqrt{\phi(p)}\)即可保证总时间复杂度是\(O(\sqrt{\phi(p)})\)

回本题

给出\(y\),\(z\),\(p\),计算满足\(y^x{\equiv}z{\mod{p}}\)的最小非负整数 \(x\)

保证\(p\)是质数。

首先考虑\(p|y\)的情况,即\({\gcd}(y,p){\not=}1\)的情况,此时不能适用BSGS算法

  • 1、\(z=0\)\(x=1\)即可
  • 2、\(z=1\)\(x=0\)即可
  • 3、others:无解

其他情况可以适用BSGS解决。

代码

#include

using namespace std;

#define ll long long
#define rg register

inline ll read(){
    ll s = 0,ww = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
    while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
    return s * ww;
}

inline void write(ll x){
    if(x < 0)putchar('-'),x = -x;
    if(x > 9)write(x / 10);
    putchar('0' + x % 10);
}

ll mod,g;

inline ll check(ll x){
    return (x % mod + mod) % mod;
}

namespace ModCalc{
    inline void Inc(ll &x,ll y,ll mod){
        x += y;if(x >= mod)x -= mod;
    }
    
    inline void Dec(ll &x,ll y,ll mod){
        x -= y;if(x < 0)x += mod;
    }
    
    inline ll Add(ll x,ll y,ll mod){
        Inc(x,y,mod);return x;
    }
    
    inline ll Sub(ll x,ll y,ll mod){
        Dec(x,y,mod);return x;
    }
}
using namespace ModCalc;

inline ll power(ll a,ll n){
    ll x = a,s = 1;
    while(n){
        if(n & 1)s = s * x % mod;
        x = x * x % mod;
        n >>= 1;
    }
    return s;
}

inline ll exgcd(ll a,ll &x,ll b,ll &y){
    if(!b){
        x = 1,y = 0;
        return a;
    }
    ll g = exgcd(b,y,a%b,x);
    y -= a / b * x;
    return g; 
}

mapM;

int main(){
    ll T = read(),opt = read();
    if(opt == 1){
        while(T--){
            ll a = read(),n = read();
            mod = read();a %= mod;
            write(power(a,n));putchar('\n');
        }
    }
    else if(opt == 2){
        while(T--){
            ll a = read(),r = read();
            mod = read();
            ll x,y;
            ll g = exgcd(a,x,mod,y);
            if(r % g != 0){
                puts("Orz, I cannot find x!");
                continue;
            }
            a /= g,r /= g,mod /= g;
            x = check(x * r);
            write(x);putchar('\n');
        }
    }
    else{
        while(T--){
            ll a = read(),r = read();
            mod = read();a %= mod,r %= mod;
            if(!a){
                if(!r)puts("1");
                else if(r == 1)puts("0");
                else puts("Orz, I cannot find x!");
                continue;
            }
            ll T = (ll)round(sqrt(mod));
            ll a_T = power(a,T);
            M.clear();
            for(rg ll i = 1,cur = r * a % mod;i <= T;i++,cur = cur * a % mod)M[cur] = i;
            ll flag = 0;
            for(rg ll i = 1,cur = a_T;i * T - T <= mod - 2;i++,cur = cur * a_T % mod)if(M.count(cur)){
                write(Sub(i*T%(mod-1),M[cur],mod-1)),putchar('\n');
                flag = 1;
                break;
            }
            if(!flag)puts("Orz, I cannot find x!");
        }
    }
    return 0;
}

你可能感兴趣的:([SDOI2011][洛谷P2485]计算器(BSGS模板))