1 条题解

  • 0
    @ 2026-5-3 15:53:25

    问题重述

    给定一个质数 pp,一个长度为 nn 的数组 aa(元素互异,且 0ai<p0 \le a_i < p),以及一个整数 kk (0k<p0 \le k < p)。
    定义运算 \oplus,表面上是“按位异或”,但实际上链接中的小游戏揭示 \oplus 表示乘法
    求满足下式的下标对 (i,j)(i, j) 的数量(1i<jn1 \le i < j \le n):

    $$(a_i \oplus a_j) \cdot (a_i^2 \oplus a_j^2) \equiv k \pmod p $$

    题意转化:\oplus 的真实含义

    题目中 [bitwise XOR operation] 的链接指向一个 Wordle 游戏。解出单词为 MULTIPLY(乘法)。
    因此实际运算为:

    • aiaj=ai×aj(modp)a_i \oplus a_j = a_i \times a_j \pmod p
    • ai2aj2=ai2×aj2(modp)a_i^2 \oplus a_j^2 = a_i^2 \times a_j^2 \pmod p

    代入原式:

    $$(a_i \times a_j) \cdot (a_i^2 \times a_j^2) \equiv k \pmod p $$ai3aj3k(modp)a_i^3 \cdot a_j^3 \equiv k \pmod p

    结论:问题转化为求

    ai3aj3k(modp)a_i^3 \cdot a_j^3 \equiv k \pmod p

    i<ji < j 的配对数量。

    算法推导

    固定 jj,我们需要快速统计在 jj 之前有多少个 ii 满足:

    ai3k(aj3)1(modp)a_i^3 \equiv k \cdot (a_j^3)^{-1} \pmod p

    由于 pp 是质数,利用费马小定理可以求逆元:
    对于任意非零元 xx,有 x1xp2(modp)x^{-1} \equiv x^{p-2} \pmod p(前提 x≢0x \not\equiv 0)。

    我们可以从左到右遍历数组,维护一个哈希表 mp,键为 ai3modpa_i^3 \bmod p,值为其出现次数。
    对于当前元素 aja_j

    1. 计算 x=aj3(modp)x = a_j^3 \pmod p
    2. 如果 x0x \neq 0,计算 inv=x1(modp)inv = x^{-1} \pmod p,则与 aja_j 配对的 aia_i 需要满足 ai3kinv(modp)a_i^3 \equiv k \cdot inv \pmod p
    3. 在答案中累加 mp[k * inv % p]
    4. 更新 mp[x]++

    注意几个特殊情况:

    • k=0k = 0:条件变为 ai3aj30(modp)a_i^3 \cdot a_j^3 \equiv 0 \pmod p。由于 pp 是质数,无零因子,即至少一个 ai30(modp)a_i^3 \equiv 0 \pmod p,即 ai=0a_i = 0
      题目保证所有元素互异,因此数组中至多一个 00
      如果存在 00,则它与任何其他元素配对均满足 0aj3=00 \cdot a_j^3 = 0,故答案为 n1n-1;否则为 00
    • aj=0a_j = 0k0k \neq 0:方程变为 0k(modp)0 \equiv k \pmod p,不成立。因此 aj=0a_j = 0 不可能与任何 ii 配对(因为 k0k \neq 0)。代码中直接 continue 跳过。

    标准程序详解

    #include <bits/stdc++.h>
    using namespace std;
    
    #define ll long long
    
    int a[300005];
    
    // 快速幂:计算 x^n mod p
    ll power(ll x, int n, int p) {
        x %= p;
        ll res = 1;
        while (n) {
            if (n & 1) res = (res * x) % p;
            x = (x * x) % p;
            n >>= 1;
        }
        return res;
    }
    
    int main() {
        ios_base::sync_with_stdio(false);
        cin.tie(NULL);
        int n, p, k;
        cin >> n >> p >> k;
        for (int i = 1; i <= n; ++i) {
            cin >> a[i];
        }
    
        // 特判 k=0
        if (k == 0) {
            // 只有数组中存在0时,0与其他任意元素配对成立,答案为 n-1
            cout << (*min_element(a + 1, a + n + 1) == 0 ? n - 1 : 0) << '\n';
            return 0;
        }
    
        map<int, int> mp;
        ll ans = 0;
        for (int i = 1; i <= n; ++i) {
            if (a[i] == 0) continue;   // k != 0 时,0无法满足方程
    
            int x = power(a[i], 3, p);          // a_i^3 mod p
            int inv = power(x, p - 2, p);       // 费马小定理求逆元
            ans += mp[(k * (ll)inv) % p];       // 统计前面满足 a_j^3 ≡ k * inv 的元素数
            ++mp[x];                            // 将当前 a_i^3 加入哈希表
        }
        cout << ans << '\n';
        return 0;
    }
    
    • 1

    信息

    ID
    6750
    时间
    4000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    1
    已通过
    1
    上传者