1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
  | // 더 많은 정보는 42jerrykim.github.io 에서 확인하세요.
#include <bits/stdc++.h>
using namespace std;
using cd = complex<double>;
const double PI = acos(-1.0);
const int MAXN = 1'000'000;
static void fft(vector<cd> &a, bool invert) {
    int n = (int)a.size();
    static vector<int> rev;
    static vector<cd> roots{cd(0, 0), cd(1, 0)};
    if ((int)rev.size() != n) {
        int k = __builtin_ctz(n);
        rev.assign(n, 0);
        for (int i = 0; i < n; i++) {
            rev[i] = 0;
            for (int j = 0; j < k; j++) if (i & (1 << j))
                rev[i] |= 1 << (k - 1 - j);
        }
    }
    if ((int)roots.size() < n) {
        int k = __builtin_ctz(roots.size());
        roots.resize(n);
        while ((1 << k) < n) {
            double ang = 2 * PI / (1 << (k + 1));
            for (int i = 1 << (k - 1); i < (1 << k); i++) {
                roots[2 * i] = roots[i];
                double a = ang * (2 * i + 1 - (1 << k));
                roots[2 * i + 1] = cd(cos(a), sin(a));
            }
            k++;
        }
    }
    for (int i = 0; i < n; i++)
        if (i < rev[i]) swap(a[i], a[rev[i]]);
    for (int len = 1; len < n; len <<= 1) {
        for (int i = 0; i < n; i += 2 * len) {
            for (int j = 0; j < len; j++) {
                cd u = a[i + j];
                cd v = a[i + j + len] * roots[len + j];
                a[i + j] = u + v;
                a[i + j + len] = u - v;
            }
        }
    }
    if (invert) {
        reverse(a.begin() + 1, a.end());
        for (cd &x : a) x /= n;
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    // Sieve up to MAXN
    vector<bool> is_prime(MAXN + 1, true);
    is_prime[0] = is_prime[1] = false;
    for (int i = 2; i * 1LL * i <= MAXN; i++) {
        if (is_prime[i]) {
            for (int j = i * i; j <= MAXN; j += i) is_prime[j] = false;
        }
    }
    // Prepare polynomial A: A[p] = 1 for all primes p (including 2)
    int need = 1;
    while (need < 2 * MAXN + 1) need <<= 1;
    vector<cd> A(need, 0);
    for (int i = 2; i <= MAXN; i++) if (is_prime[i]) A[i] = 1.0;
    // Convolution A * A via FFT
    fft(A, false);
    for (int i = 0; i < need; i++) A[i] *= A[i];
    fft(A, true);
    // Round to nearest integer
    vector<long long> conv(2 * MAXN + 1, 0);
    for (int i = 0; i <= 2 * MAXN; i++) {
        conv[i] = llround(A[i].real());
    }
    int T;
    if (!(cin >> T)) return 0;
    while (T--) {
        int N; cin >> N; // even, 2 < N ≤ 1e6
        // Ordered pairs from convolution = conv[N]
        // Unordered count = (conv[N] + [N/2 is prime]) / 2
        long long sym = (N % 2 == 0 && is_prime[N / 2]) ? 1 : 0;
        long long ans = (conv[N] + sym) / 2;
        cout << ans << '\n';
    }
    return 0;
}
  |