其他分享
首页 > 其他分享> > P2485 [SDOI2011] 费马小定理 + Baby Step, Giant Step

P2485 [SDOI2011] 费马小定理 + Baby Step, Giant Step

作者:互联网

题意

传送门 P2485 [SDOI2011]计算器

题解

p p p 为质数,若 y , p y,p y,p 不互质,那么有 p ∣ y p|y p∣y,特判此类情况。之后讨论 y , p y,p y,p 互质的情况。

考虑任务一,计算 y z m o d    p y^z\mod p yzmodp,快速幂求解即可。

考虑任务二,计算满足 x y ≡ z m o d    p xy\equiv z\mod p xy≡zmodp 的最小非负整数 x x x。由于 y , p y,p y,p 互质,则 y y y 存在模 p p p 意义下的逆元,根据费马小定理, y − 1 = y p − 2 m o d    p y^{-1}=y^{p-2}\mod p y−1=yp−2modp,则 x = z y − 1 m o d    p x=zy^{-1}\mod p x=zy−1modp。

考虑任务三,计算满足 y x ≡ z m o d    p y^x\equiv z\mod p yx≡zmodp 的最小非负整数 x x x。由于 y , p y,p y,p 互质,则可以在模 p p p 意义下进行关于 y y y 的乘、除法运算,使用 B a b y   S t e p , G i a n t   S t e p Baby\ Step, Giant\ Step Baby Step,Giant Step 算法求解。基本思路是平方分割。根据费马小定理,有 y p − 1 ≡ 1 m o d    p y^{p-1}\equiv 1\mod p yp−1≡1modp,那么 x x x 的解只用考虑模 p − 1 p-1 p−1 的情况。设 x = i × t − j x=i\times t-j x=i×t−j,其中 t = ⌈ q ⌉ t=\lceil\sqrt q\rceil t=⌈q ​⌉, 0 ≤ j < t 0\leq j<t 0≤j<t,则方程变为 ( a t ) i ≡ b × a j m o d    p (a^t)^i\equiv b\times a^j\mod p (at)i≡b×ajmodp。枚举 i ∈ [ 0 , t ] i\in [0,t] i∈[0,t],在 H a s h Hash Hash 表中查找是否存在满足条件的 j j j 即可。时间复杂度 O ( p ) O(\sqrt p) O(p ​)。

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

ll gcd(ll a, ll b)
{
    return b == 0 ? a : gcd(b, a % b);
}

ll mod_pow(ll x, ll n, ll m)
{
    ll res = 1;
    while (n)
    {
        if (n & 1)
            res = res * x % m;
        x = x * x % m;
        n >>= 1;
    }
    return res;
}

ll baby_step_giant_step(ll a, ll b, ll p)
{
    mp hash;
    ll t = sqrt(p) + 1, x = b % p;
    for (int i = 0; i < t; ++i)
    {
        hash[x] = i;
        x = x * a % p;
    }
    a = mod_pow(a, t, p), x = 1;
    for (int i = 0; i <= t; ++i)
    {
        int j = hash.find(x) == hash.end() ? -1 : hash[x];
        if (j >= 0 && i * t - j >= 0)
            return i * t - j;
        x = x * a % p;
    }
    return -1;
}

int main()
{
    int t, k;
    scanf("%d%d", &t, &k);
    while (t--)
    {
        ll y, z, p, res = -1;
        scanf("%lld%lld%lld", &y, &z, &p);
        ll d = gcd(y, p);
        if (k == 1)
            res = d == 1 ? mod_pow(y % p, z % (p - 1), p) : 0;
        else if (k == 2)
            res = d == 1 ? z * mod_pow(y, p - 2, p) % p : (z % p != 0 ? -1 : 0);
        else
            res = d == 1 ? baby_step_giant_step(y, z, p) : (z % p != 0 ? -1 : 1);
        if (res >= 0)
            printf("%lld\n", res);
        else
            puts("Orz, I cannot find x!");
    }
    return 0;
}

标签:Giant,return,res,ll,SDOI2011,Step,hash,mod
来源: https://blog.csdn.net/neweryyy/article/details/110674812