设 \(p_k=\sum\limits_{i=1}^kA_iX^i\),且 \(p_0=0\)。则 \(\forall 1\le i\le j\le N,\,W(i,j)=\dfrac{p_j-p_{i-1}}{X^i}\)。于是有
\[\begin{align*}P&=\prod_{i=1}^N\prod_{j=i}^NW(i,j)^2\\&=\left(\prod_{i=0}^N\prod_{j=i+1}^N\dfrac{p_j-p_i}{X^{i+1}}\right)^2\\&=\dfrac{\left(\prod\limits_{i=0}^N\prod\limits_{j=i+1}^N(p_j-p_i)\right)^2}{X^{2\times \sum\limits_{i=1}^Ni\cdot(N-i)}}\end{align*} \]上式中的分母很好计算,现在主要考虑如何计算分子。
注意到 \((p_j-p_i)^2=-(p_j-p_i)\cdot(p_i-p_j)\),则可以考虑将分子变形为
\[\begin{align*}\operatorname{Numerator}(P)&=(-1)^{\frac{N\cdot(N+1)}{2}}\prod_{i=0}^{N}\prod_{j\neq i}(p_j-p_i)\end{align*} \]设 \(f(i)=\prod\limits_{j\neq i}(p_i-p_j)\),那么有
\[\begin{align*}\operatorname{Numerator}(P)&=(-1)^{\frac{N\cdot(N+1)}{2}}\prod_{i=0}^{N}(-1)^{N}f(i)\end{align*} \]可以考虑直接将 \(f(0\ldots N-1)\) 求出来。
注意到 \(f(i)\) 的结构非常相似,因此我们的想法是找到一个多项式 \(F(x)\) 满足 \(f(i)=F(p_i)\)。如果找到了这样的 \(F(x)\),那么就可以对 \(F(x)\) 做一遍多项式多点求值来求出 \(f(i)\)。
于是我们可以考虑类似于拉格朗日插值定理那样的方式去构造:设 \(F(x)=\sum\limits_{i=0}^N\prod\limits_{j\neq i}(x-p_j)\),则有等式 \(F(p_i)=\prod\limits_{j\neq i}(p_i-p_j)=f(i)\)。那么又该如何将 \(F(x)\) 求出来呢?
让我们先考虑另一个多项式 \(G(x)=\prod\limits_{i=0}^N(x-p_i)\)。那么就有 \(F(x)=\sum\limits_{i=0}^N\dfrac{G(x)}{x-p_i}=G'(x)\)。于是只要将 \(G(x)\) 求出来再对其求导就行了。
至于如何求 \(G(x)\) 可以用启发式合并+NTT的方法,时间复杂度为 \(\mathcal O(N\log ^2N)\);对 \(F(x)\) 进行多项式多点求值的时间复杂度也是 \(\mathcal O(N\log ^2N)\) 的。总时间复杂度就是线对平方。
#include <bits/stdc++.h> using namespace std; /** 此处省略多项式全家桶的模板 **/ static constexpr value_t mod = poly::P; inline value_t add(value_t x, value_t y) { return (x += y) >= mod ? x - mod : x; } inline value_t mul(value_t x, value_t y) { return (int64_t)x * y % mod; } inline value_t &add_eq(value_t &x, value_t y) { return x = add(x, y); } inline value_t &mul_eq(value_t &x, value_t y) { return x = mul(x, y); } inline value_t qpow(value_t x, int64_t y) { value_t r = 1; for (; y; y >>= 1, mul_eq(x, x)) (y & 1) && (mul_eq(r, x)); return r; } // qpow static constexpr int Maxn = 1e5 + 5; int N; value_t X, iX, Xp, A[Maxn]; value_t p[Maxn], P; poly getG(int l, int r) { if (l == r) return poly{!p[l] ? 0 : mod - p[l], 1}; int mid = (l + r) >> 1; return getG(l, mid) * getG(mid + 1, r); } // getG int main(void) { int tests; scanf("%d", &tests); while (tests--) { scanf("%d%u", &N, &X); p[0] = 0; Xp = 1; iX = qpow(X, mod - 2); for (int i = 1; i <= N; ++i) { scanf("%u", &A[i]); p[i] = add(p[i - 1], mul(A[i], mul_eq(Xp, X))); } auto f = getG(0, N).derivative().evaluate(vector(p, p + N + 1)); bool neg = (((int64_t)N * (N + 1) / 2) % 2 == 1); value_t num = 1; for (int i = 0; i <= N; ++i) mul_eq(num, f[i]); int64_t Exp = (int64_t)N * (N + 1) * (N + 2) / 3; Exp %= (mod - 1); value_t dinom = qpow(iX, Exp); P = mul_eq(num, dinom); printf("%u\n", neg ? (!P ? 0 : mod - P) : P); } exit(EXIT_SUCCESS); } // main