CodeChef Weird Product

CodeChef Weird Product

​ 设 \(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

上一篇:十步图解CSS的position


下一篇:论文解读(node2vec)《node2vec Scalable Feature Learning for Networks》