QOJ.ac

QOJ

IDProblemSubmitterResultTimeMemoryLanguageFile sizeSubmit timeJudge time
#203387#5. 在线 O(1) 逆元_LAP_100 5551ms21080kbC++141.8kb2023-10-06 17:07:152023-10-06 17:07:15

Judging History

This is a historical verdict posted at 2023-10-06 17:07:15.

  • [2024-11-05 21:52:58]
  • 管理员手动重测本题所有提交记录
  • Verdict: 60
  • Time: 3858ms
  • Memory: 21216kb
  • [2023-10-06 17:07:15]
  • Judged
  • Verdict: 100
  • Time: 5551ms
  • Memory: 21080kb
  • [2023-10-06 17:07:15]
  • Submitted

answer

#include "inv.h"
#include <bits/stdc++.h>

using namespace std;

//预处理 Farey 序列 $F_{ \sqrt[3]{p} }$ 和 $\sqrt[3]{p}^2$ 内数的逆元
int n, m, P; vector<int> F, init_inv;  // n = \sqrt[3]{p}, m = n^2
vector<int> sum, frac;
inline long long ksm(long long a, int b, int Mod) {
    long long r = 1;
    while(b) {
        if(b & 1) r = r * a % Mod;
        b >>= 1, a = a * a % Mod;
    }
    return r;
}

void init(int p) {
    ::P = p, n = (int)pow(p, 1.0 / 3) + 2; m = n * n;
    sum = vector<int>(m + 1, 0), frac = vector<int>(m + 1, 0), init_inv.resize(m + 1);

    // 根据 (\lfloor x / y \times n^2) \rfloor 互不相同预处理Farey序列
    for(int x = 1; x <= n - 1; x ++) for(int y = 0; y <= x; y ++) {
        int i = y * m / x; if(!sum[i]) sum[i] = 1, frac[i] = y * n + x;
    }
    for(int i = 1; i <= m; i ++) sum[i] += sum[i - 1];
    for(int i = 0; i <= m; i ++) if(frac[i]) F.emplace_back(frac[i]);
    
    init_inv[1] = 1;
    vector<int> d(m + 1, 0), primes;
    for(int i = 2; i <= m; i ++) {
        if(!d[i]) primes.emplace_back(i), init_inv[i] = ksm(i, p - 2, p);
        for(auto pr : primes) {
            if(1ll * pr * i > m) break;
            d[pr * i] = pr, init_inv[pr * i] = 1ll * init_inv[pr] * init_inv[i] % P;
            if(i % pr == 0) break;
        }
    }
}
int inv(int x) {
    int i = 1ll * x * m / P, k = sum[i]; long long f, t; int p, q;
    if(k < F.size()) {
        f = F[k], p = f / n, q = f - n * p, t = 1ll * x * q - 1ll * p * P;
        if(abs(t) <= m) return 1ll * q * (t > 0 ? init_inv[t] : P - init_inv[-t]) % P;
    }
    if(--k >= 0) {
        f = F[k], p = f / n, q = f - n * p, t = 1ll * x * q - 1ll * p * P;
        if(abs(t) <= m) return 1ll * q * (t > 0 ? init_inv[t] : P - init_inv[-t]) % P;
    }
    return -1;
}

Details

Test #1:

score: 30
Accepted
time: 40ms
memory: 21072kb

Test #2:

score: 40
Accepted
time: 590ms
memory: 21080kb

Test #3:

score: 30
Accepted
time: 5551ms
memory: 21076kb