[trick] AGC047C Product Modulo

\(\texttt{link}\)

\(\sum\limits_{i=1}^n\sum\limits_{j=i+1}^n (a_i * a_j \bmod P), P = 200003\)

\(P\) 的一个原根 \(g = 2\),那么 \([1,P-1]\) 可以映射到 \(g^{[0,P-2]}\) 上。

\(a = g^x,b = g^y\),那么有 \(a*b \bmod P = g^x * g^y \bmod P = g^{(x+y)\bmod {(P-1)}}\),直接 \(fft\) 即可。

时间复杂度 \(\mathrm{O(P\log P)}\)

\(\texttt{Code:}\)

#include <bits/stdc++.h>
#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
int read() {
    int x = 0; int f = 0; char c = getchar();
    while (!isdigit(c)) f |= c == '-', c = getchar();
    while (isdigit(c)) x = x * 10 + (c ^ 48), c = getchar();
    return f ? -x : x;
}
const int cmd = 200003;
int fpow(int a, int b) {
    int res = 1;
    for (; b; b >>= 1, a = 1ll * a * a % cmd)
        if (b & 1) res = 1ll * res * a % cmd;
    return res;
}
int add(int a, int b) {a += b; return a < cmd ? a : a - cmd;}
int sub(int a, int b) {a -= b; return a < 0 ? a + cmd : a;}
const int N = (1 << 19) + 5;
namespace Poly {
    struct CP {
        double x, y;
        CP operator + (const CP &a) const {return (CP){x + a.x, y + a.y};}
        CP operator - (const CP &a) const {return (CP){x - a.x, y - a.y};}
        CP operator * (const CP &a) const {return (CP){x * a.x - y * a.y, x * a.y + y * a.x};}
    };
    const double pi = acos(-1);
    int rev[N];
    void fft(CP *f, int n, int tp) {
        for (int i = 0; i < n; i++) {
            rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? n >> 1 : 0);
            if (i < rev[i]) swap(f[i], f[rev[i]]);
        }
        for (int len = 2; len <= n; len <<= 1) {
            CP w0 = (CP){cos(2.0 * pi / len), sin(2.0 * pi / len) * tp};
            for (int s = 0; s < n; s += len) {
                CP w = (CP){1, 0};
                for (int i = 0; i < (len >> 1); i++) {
                    CP cur = w * f[s + (len >> 1) + i];
                    f[s + (len >> 1) + i] = f[s + i] - cur;
                    f[s + i] = f[s + i] + cur;
                    w = w * w0;
                }
            }
        }if (tp == -1)
            for (int i = 0; i < n; i++) f[i].x = (ll)(f[i].x / n + 0.5);
    }
    void tms(CP *f, CP *g, int n) {
        for (int i = 0; i < n; i++) f[i] = f[i] * g[i];
    }
    void FFT(CP *f, int m) {
        int n = 1; for (; n <= m + m; n <<= 1);
        fft(f, n, 1); tms(f, f, n);
        fft(f, n, -1);
    }
}using namespace Poly;
int n, g[N], ys[N], cnt[N];
CP f[N]; ll ans;
int main() {
    #ifdef LOCAL
    freopen("a.in", "r", stdin);
    freopen("a.out", "w", stdout);
    #endif
    ys[g[0] = 1] = 0;
    for (int i = 1; i < cmd - 1; i++) {
        g[i] = (g[i - 1] << 1) % cmd;
        ys[g[i]] = i;
    }
    n = read();
    for (int i = 1; i <= n; i++) {
        int a = read();
        if (a) ++cnt[ys[a]], ans -= 1ll * a * a % cmd;
    }
    for (int i = 0; i < cmd - 1; i++) f[i] = (CP){(double)cnt[i], 0};
    FFT(f, cmd - 2);
    for (int i = 0; i < cmd - 1; i++)
        ans += 1ll * g[i] * ((ll)f[i].x + (ll)f[i + cmd - 1].x);
    printf("%lld", ans >> 1);
    return 0;
}
posted @ 2021-12-18 12:04  klii  阅读(63)  评论(0)    收藏  举报