1 条题解

  • 0
    @ 2026-10-26 14:35:24

    思路与算法

    K=1用快速幂。K=2先约去模p,底数非零时用费马逆元计算z/y;底数为0时按z是否为0决定最小解0或无解。K=3先处理目标1的x=0及底数0,再对非零底数使用BSGS:存y^j的最小j,逐块检查z*(y^m)^(-i),首次找到给出i*m+j。

    正确性说明

    快速幂按二进制分解指数正确。质数模p下非零底数可逆,一次同余有唯一剩余类,0至p-1的代表最小。非零底数的幂周期整除p-1,BSGS把所有可能指数按连续m长度分块,i递增且每个baby值存最小j,所以第一次命中即最小非负指数。底数0与目标0不满足互质前提,单独分支避免错误求逆。

    复杂度

    每组快速幂/逆元O(log p),BSGS期望O(√p)时间和空间,哈希表创建、预留与baby表插入均计入;T≤10、p≤10^9。乘积小于10^18,long long安全。不存在时输出固定英文。

    易错点

    y和z可能是p的倍数,必须先取模。K=3目标1时x=0即使y为0也按0次乘法得到1;目标0且y非零则无解。独立小模数遍历完整幂周期,大模数样例选可逐次乘到首个命中的指数,证明最小性,不依赖另一个BSGS。

    参考代码(C++11)

    #include <bits/stdc++.h>
    using namespace std;
    long long power(long long a, long long e, long long p) {
        long long r = 1 % p;
        for (a %= p; e; e /= 2, a = a * a % p)
            if (e & 1)
                r = r * a % p;
        return r;
    }
    long long logDiscrete(long long y, long long z, long long p) {
        y %= p;
        z %= p;
        if (z == 1)
            return 0;
        if (y == 0)
            return z == 0 ? 1 : -1;
        if (z == 0)
            return -1;
        long long m = sqrtl(p) + 1;
        unordered_map<long long, long long> baby;
        baby.reserve(m * 2);
        long long a = 1;
        for (long long j = 0; j < m; ++j) {
            baby.emplace(a, j);
            a = a * y % p;
        }
        long long factor = power(a, p - 2, p), value = z;
        for (long long i = 0; i <= m; ++i) {
            auto it = baby.find(value);
            if (it != baby.end())
                return i * m + it->second;
            value = value * factor % p;
        }
        return -1;
    }
    int main() {
        int T, K;
        cin >> T >> K;
        while (T--) {
            long long y, z, p;
            cin >> y >> z >> p;
            long long result;
            if (K == 1)
                result = power(y, z, p);
            else if (K == 2) {
                y %= p;
                z %= p;
                result = y == 0 ? (z == 0 ? 0 : -1) : z * power(y, p - 2, p) % p;
            } else
                result = logDiscrete(y, z, p);
            if (result < 0)
                cout << "Orz,I cannot find x!\n";
            else
                cout << result << '\n';
        }
    }
    
    • 1

    信息

    ID
    1776
    时间
    1000ms
    内存
    512MiB
    难度
    普及+
    标签
    递交数
    1
    已通过
    1
    上传者