跳转至

多項式初等函數

本頁面包含多項式常見的初等函數操作。具體而言,本頁面包含如下內容:

  1. 多項式求逆
  2. 多項式開方
  3. 多項式除法
  4. 多項式取模
  5. 多項式指數函數
  6. 多項式對數函數
  7. 多項式三角函數
  8. 多項式反三角函數
初等函數與非初等函數

初等函數的定義如下1

若域 \(F\) 中存在映射 \(u\to \partial u\) 滿足:

  1. \(\partial(u+v)=\partial u+\partial v\)
  2. \(\partial(uv)=u\partial v+v\partial u\)

則稱這個域為 微分域

若微分域 \(F\) 上的函數 \(u\) 滿足以下的任意一條條件,則稱該函數 \(u\) 為初等函數:

  1. \(u\)\(F\) 上的代數函數。
  2. \(u\)\(F\) 上的指數性函數,即存在 \(a\in F\) 使得 \(\partial u=u\partial a\).
  3. \(u\)\(F\) 上的對數性函數,即存在 \(a\in F\) 使得 \(\partial u=\frac{\partial a}{a}\).

以下是常見的初等函數:

  1. 代數函數:存在有限次多項式 \(P\) 使得 \(P(f(x))=0\) 的函數 \(f(x)\),如 \(2x+1\),\(\sqrt{x}\),\((1+x^2)^{-1}\),\(|x|\).
  2. 指數函數
  3. 對數函數
  4. 三角函數
  5. 反三角函數
  6. 雙曲函數
  7. 反雙曲函數
  8. 以上函數的複合,如:

    \[ \frac{\mathrm{e}^{\tan x}}{1+x^2}\sin\left(\sqrt{1+\ln^2 x}\right) \]
    \[ -\mathrm{i} \ln\left(x+\mathrm{i}\sqrt{1-x^2}\right) \]

以下是常見的非初等函數:

  1. 誤差函數:

    \[ \operatorname{erf}(x):=\frac{2}{\sqrt{\pi}}\int_{0}^{x}\exp\left(-t^2\right)\mathrm{d}t \]

多項式求逆

給定多項式 \(f\left(x\right)\),求 \(f^{-1}\left(x\right)\)

解法

倍增法

首先,易知

\[ \left[x^{0}\right]f^{-1}\left(x\right)=\left(\left[x^{0}\right]f\left(x\right)\right)^{-1} \]

假設現在已經求出了 \(f\left(x\right)\) 在模 \(x^{\left\lceil\frac{n}{2}\right\rceil}\) 意義下的逆元 \(f^{-1}_{0}\left(x\right)\)。 有:

\[ \begin{aligned} f\left(x\right)f^{-1}_{0}\left(x\right)&\equiv 1 &\pmod{x^{\left\lceil\frac{n}{2}\right\rceil}}\\ f\left(x\right)f^{-1}\left(x\right)&\equiv 1 &\pmod{x^{\left\lceil\frac{n}{2}\right\rceil}}\\ f^{-1}\left(x\right)-f^{-1}_{0}\left(x\right)&\equiv 0 &\pmod{x^{\left\lceil\frac{n}{2}\right\rceil}} \end{aligned} \]

兩邊平方可得:

\[ f^{-2}\left(x\right)-2f^{-1}\left(x\right)f^{-1}_{0}\left(x\right)+f^{-2}_{0}\left(x\right)\equiv 0 \pmod{x^{n}} \]

兩邊同乘 \(f\left(x\right)\) 並移項可得:

\[ f^{-1}\left(x\right)\equiv f^{-1}_{0}\left(x\right)\left(2-f\left(x\right)f^{-1}_{0}\left(x\right)\right) \pmod{x^{n}} \]

遞歸計算即可。

時間複雜度

\[ T\left(n\right)=T\left(\frac{n}{2}\right)+O\left(n\log{n}\right)=O\left(n\log{n}\right) \]

Newton's Method

參見 Newton's Method.

Graeffe 法

欲求 \(f^{-1}(x)\bmod x^{2n}\) 考慮

\[ \begin{aligned} f^{-1}(x)\bmod x^{2n}&= f(-x)(f(x)f(-x))^{-1}\bmod x^{2n}\\ &=f(-x)g^{-1}(x^2)\bmod x^{2n} \end{aligned} \]

只需求出 \(g^{-1}(x)\bmod x^n\) 即可還原出 \(g^{-1}(x^2)\bmod x^{2n}\) 因為 \(f(x)f(-x)\) 是偶函數,時間複雜度同上。

代碼

多項式求逆
 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
constexpr int maxn = 262144;
constexpr int mod = 998244353;

using i64 = long long;
using poly_t = int[maxn];
using poly = int *const;

void polyinv(const poly &h, const int n, poly &f) {
  /* f = 1 / h = f_0 (2 - f_0 h) */
  static poly_t inv_t;
  std::fill(f, f + n + n, 0);
  f[0] = fpow(h[0], mod - 2);
  for (int t = 2; t <= n; t <<= 1) {
    const int t2 = t << 1;
    std::copy(h, h + t, inv_t);
    std::fill(inv_t + t, inv_t + t2, 0);

    DFT(f, t2);
    DFT(inv_t, t2);
    for (int i = 0; i != t2; ++i)
      f[i] = (i64)f[i] * sub(2, (i64)f[i] * inv_t[i] % mod) % mod;
    IDFT(f, t2);

    std::fill(f + t, f + t2, 0);
  }
}

例題

  1. 有標號簡單無向連通圖計數:「POJ 1737」Connected Graph

多項式開方

給定多項式 \(g\left(x\right)\),求 \(f\left(x\right)\),滿足:

\[ f^{2}\left(x\right)\equiv g\left(x\right) \pmod{x^{n}} \]

解法

倍增法

首先討論 \(\left[x^0\right]g(x)\) 不為 \(0\) 的情況。

易知:

\[ \left[x^0\right]f(x) = \sqrt{\left[x^0\right]g(x)} \]

\(\left[x^0\right]g(x)\) 沒有平方根,則多項式 \(g(x)\) 沒有平方根。

\(\left[x^0\right]g(x)\) 可能有多個平方根,選取不同的根會求出不同的 \(f(x)\)

假設現在已經求出了 \(g\left(x\right)\) 在模 \(x^{\left\lceil\frac{n}{2}\right\rceil}\) 意義下的平方根 \(f_{0}\left(x\right)\),則有:

\[ \begin{aligned} f_{0}^{2}\left(x\right)&\equiv g\left(x\right) &\pmod{x^{\left\lceil\frac{n}{2}\right\rceil}}\\ f_{0}^{2}\left(x\right)-g\left(x\right)&\equiv 0 &\pmod{x^{\left\lceil\frac{n}{2}\right\rceil}}\\ \left(f_{0}^{2}\left(x\right)-g\left(x\right)\right)^{2}&\equiv 0 &\pmod{x^{n}}\\ \left(f_{0}^{2}\left(x\right)+g\left(x\right)\right)^{2}&\equiv 4f_{0}^{2}\left(x\right)g\left(x\right) &\pmod{x^{n}}\\ \left(\frac{f_{0}^{2}\left(x\right)+g\left(x\right)}{2f_{0}\left(x\right)}\right)^{2}&\equiv g\left(x\right) &\pmod{x^{n}}\\ \frac{f_{0}^{2}\left(x\right)+g\left(x\right)}{2f_{0}\left(x\right)}&\equiv f\left(x\right) &\pmod{x^{n}}\\ 2^{-1}f_{0}\left(x\right)+2^{-1}f_{0}^{-1}\left(x\right)g\left(x\right)&\equiv f\left(x\right) &\pmod{x^{n}} \end{aligned} \]

倍增計算即可。

時間複雜度

\[ T\left(n\right)=T\left(\frac{n}{2}\right)+O\left(n\log{n}\right)=O\left(n\log{n}\right) \]

還有一種常數較小的寫法就是在倍增維護 \(f\left(x\right)\) 的時候同時維護 \(f^{-1}\left(x\right)\) 而不是每次都求逆。

\(\left[x^{0}\right]g\left(x\right)\neq 1\) 時,可能需要使用二次剩餘來計算 \(\left[x^{0}\right]f\left(x\right)\)

上述方法需要知道 \(f_{0}(x)\) 的逆,所以常數項不能為 \(0\)

\(\left[x^0\right]g(x) = 0\),則將 \(g(x)\) 分解成 \(x^{k}h(x)\),其中 \(\left[x^0\right]h(x) \not = 0\)

  • \(k\) 是奇數,則 \(g(x)\) 沒有平方根。

  • \(k\) 是偶數,則求出 \(h(x)\) 的平方根 \(\sqrt{h(x)}\),然後得到 \(f(x) \equiv x^{k/2} \sqrt{h(x)} \pmod{x^{n}}\)

洛谷模板題 P5205【模板】多項式開根 參考代碼
  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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <bits/stdc++.h>
using namespace std;

const int maxn = 1 << 20, mod = 998244353;

int a[maxn], b[maxn], g[maxn], gg[maxn];

int qpow(int x, int y) {  // 快速幂
  int ans = 1;

  while (y) {
    if (y & 1) {
      ans = (long long)1 * ans * x % mod;
    }
    x = (long long)1 * x * x % mod;
    y >>= 1;
  }
  return ans;
}

int inv2 = qpow(2, mod - 2);  // 逆元

void change(int *f, int len) {
  for (int i = 1, j = len / 2; i < len - 1; i++) {
    if (i < j) {
      swap(f[i], f[j]);
    }

    int k = len / 2;
    while (j >= k) {
      j -= k;
      k /= 2;
    }
    if (j < k) {
      j += k;
    }
  }
}

void NTT(int *f, int len, int type) {  // NTT
  change(f, len);

  for (int q = 2; q <= len; q <<= 1) {
    int nxt = qpow(3, (mod - 1) / q);
    for (int i = 0; i < len; i += q) {
      int w = 1;

      for (int k = i; k < i + (q >> 1); k++) {
        int x = f[k];
        int y = (long long)1 * w * f[k + (q / 2)] % mod;

        f[k] = (x + y) % mod;
        f[k + (q / 2)] = (x - y + mod) % mod;
        w = (long long)1 * w * nxt % mod;
      }
    }
  }

  if (type == -1) {
    reverse(f + 1, f + len);
    int iv = qpow(len, mod - 2);

    for (int i = 0; i < len; i++) {
      f[i] = (long long)1 * f[i] * iv % mod;
    }
  }
}

void inv(int deg, int *f, int *h) {  // 求逆元
  if (deg == 1) {
    h[0] = qpow(f[0], mod - 2);
    return;
  }

  inv(deg + 1 >> 1, f, h);

  int len = 1;
  while (len < deg * 2) {  // 倍增
    len *= 2;
  }

  copy(f, f + deg, gg);
  fill(gg + deg, gg + len, 0);

  NTT(gg, len, 1);
  NTT(h, len, 1);
  for (int i = 0; i < len; i++) {
    h[i] = (long long)1 * (2 - (long long)1 * gg[i] * h[i] % mod + mod) % mod *
           h[i] % mod;
  }

  NTT(h, len, -1);
  fill(h + deg, h + len, 0);
}

int n, t[maxn];

// deg:次数
// f:被开根数组
// h:答案数组
void sqrt(int deg, int *f, int *h) {
  if (deg == 1) {
    h[0] = 1;
    return;
  }

  sqrt(deg + 1 >> 1, f, h);

  int len = 1;
  while (len < deg * 2) {  // 倍增
    len *= 2;
  }
  fill(g, g + len, 0);
  inv(deg, h, g);
  copy(f, f + deg, t);
  fill(t + deg, t + len, 0);
  NTT(t, len, 1);
  NTT(g, len, 1);
  NTT(h, len, 1);

  for (int i = 0; i < len; i++) {
    h[i] = (long long)1 * inv2 *
           ((long long)1 * h[i] % mod + (long long)1 * g[i] * t[i] % mod) % mod;
  }
  NTT(h, len, -1);
  fill(h + deg, h + len, 0);
}

int main() {
  cin >> n;

  for (int i = 0; i < n; i++) {
    scanf("%d", &a[i]);
  }
  sqrt(n, a, b);

  for (int i = 0; i < n; i++) {
    printf("%d ", b[i]);
  }

  return 0;
}

Newton's Method

參見 Newton's Method.

例題

  1. 「Codeforces Round #250」E. The Child and Binary Tree

多項式除法 & 取模

給定多項式 \(f\left(x\right),g\left(x\right)\),求 \(g\left(x\right)\)\(f\left(x\right)\) 的商 \(Q\left(x\right)\) 和餘數 \(R\left(x\right)\)

解法

發現若能消除 \(R\left(x\right)\) 的影響則可直接 多項式求逆 解決。

考慮構造變換

\[ f^{R}\left(x\right)=x^{\operatorname{deg}{f}}f\left(\frac{1}{x}\right) \]

觀察可知其實質為反轉 \(f\left(x\right)\) 的係數。

\(n=\operatorname{deg}{f},m=\operatorname{deg}{g}\)

\(f\left(x\right)=Q\left(x\right)g\left(x\right)+R\left(x\right)\) 中的 \(x\) 替換成 \(\frac{1}{x}\) 並將其兩邊都乘上 \(x^{n}\),得到:

\[ \begin{aligned} x^{n}f\left(\frac{1}{x}\right)&=x^{n-m}Q\left(\frac{1}{x}\right)x^{m}g\left(\frac{1}{x}\right)+x^{n-m+1}x^{m-1}R\left(\frac{1}{x}\right)\\ f^{R}\left(x\right)&=Q^{R}\left(x\right)g^{R}\left(x\right)+x^{n-m+1}R^{R}\left(x\right) \end{aligned} \]

注意到上式中 \(R^{R}\left(x\right)\) 的係數為 \(x^{n-m+1}\),則將其放到模 \(x^{n-m+1}\) 意義下即可消除 \(R^{R}\left(x\right)\) 帶來的影響。

又因 \(Q^{R}\left(x\right)\) 的次數為 \(\left(n-m\right)<\left(n-m+1\right)\),故 \(Q^{R}\left(x\right)\) 不會受到影響。

則:

\[ f^{R}\left(x\right)\equiv Q^{R}\left(x\right)g^{R}\left(x\right)\pmod{x^{n-m+1}} \]

使用多項式求逆即可求出 \(Q\left(x\right)\),將其反代即可得到 \(R\left(x\right)\)

時間複雜度 \(O\left(n\log{n}\right)\)

多項式對數函數 & 指數函數

給定多項式 \(f(x)\),求模 \(x^{n}\) 意義下的 \(\ln{f(x)}\)\(\exp{f(x)}\)

解法

普通方法

首先,對於多項式 \(f(x)\),若 \(\ln{f(x)}\) 存在,則由其 定義,其必須滿足:

\[ [x^{0}]f(x)=1 \]

\(\ln{f(x)}\) 求導再積分,可得:

\[ \begin{aligned} \frac{\mathrm{d} \ln{f(x)}}{\mathrm{d} x} & \equiv \frac{f'(x)}{f(x)} & \pmod{x^{n}} \\ \ln{f(x)} & \equiv \int \mathrm{d} \ln{x} \equiv \int\frac{f'(x)}{f(x)} \mathrm{d} x & \pmod{x^{n}} \end{aligned} \]

多項式的求導,積分時間複雜度為 \(O(n)\),求逆時間複雜度為 \(O(n\log{n})\),故多項式求 \(\ln\) 時間複雜度 \(O(n\log{n})\)

首先,對於多項式 \(f(x)\),若 \(\exp{f(x)}\) 存在,則其必須滿足:

\[ [x^{0}]f(x)=0 \]

否則 \(\exp{f(x)}\) 的常數項不收斂。

\(\exp{f(x)}\) 求導,可得:

\[ \frac{\mathrm{d} \exp{f(x)}}{\mathrm{d} x} \equiv \exp{f(x)}f'(x)\pmod{x^{n}} \]

比較兩邊係數可得:

\[ [x^{n-1}]\frac{\mathrm{d} \exp{f(x)}}{\mathrm{d} x} = \sum_{i = 0}^{n - 1} \left([x^{i}]\exp{f(x)}\right) \left([x^{n-i-1}]f'(x)\right) \]
\[ n[x^{n}]\exp{f(x)} = \sum_{i = 0}^{n - 1} \left([x^{i}]\exp{f(x)}\right) \left((n - i)[x^{n - i}]f(x)\right) \]

使用分治 FFT 即可解決。

時間複雜度 \(O(n\log^{2}{n})\)

Newton's Method

使用 Newton's Method 即可在 \(O(n\log{n})\) 的時間複雜度內解決多項式 \(\exp\)

代碼

多項式 ln/exp
 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
constexpr int maxn = 262144;
constexpr int mod = 998244353;

using i64 = long long;
using poly_t = int[maxn];
using poly = int *const;

void derivative(const poly &h, const int n, poly &f) {
  for (int i = 1; i != n; ++i) f[i - 1] = (i64)h[i] * i % mod;
  f[n - 1] = 0;
}

void integrate(const poly &h, const int n, poly &f) {
  for (int i = n - 1; i; --i) f[i] = (i64)h[i - 1] * inv[i] % mod;
  f[0] = 0; /* C */
}

void polyln(const poly &h, const int n, poly &f) {
  /* f = ln h = ∫ h' / h dx */
  assert(h[0] == 1);
  static poly_t ln_t;
  const int t = n << 1;

  derivative(h, n, ln_t);
  std::fill(ln_t + n, ln_t + t, 0);
  polyinv(h, n, f);

  DFT(ln_t, t);
  DFT(f, t);
  for (int i = 0; i != t; ++i) ln_t[i] = (i64)ln_t[i] * f[i] % mod;
  IDFT(ln_t, t);

  integrate(ln_t, n, f);
}

void polyexp(const poly &h, const int n, poly &f) {
  /* f = exp(h) = f_0 (1 - ln f_0 + h) */
  assert(h[0] == 0);
  static poly_t exp_t;
  std::fill(f, f + n + n, 0);
  f[0] = 1;
  for (int t = 2; t <= n; t <<= 1) {
    const int t2 = t << 1;

    polyln(f, t, exp_t);
    exp_t[0] = sub(pls(h[0], 1), exp_t[0]);
    for (int i = 1; i != t; ++i) exp_t[i] = sub(h[i], exp_t[i]);
    std::fill(exp_t + t, exp_t + t2, 0);

    DFT(f, t2);
    DFT(exp_t, t2);
    for (int i = 0; i != t2; ++i) f[i] = (i64)f[i] * exp_t[i] % mod;
    IDFT(f, t2);

    std::fill(f + t, f + t2, 0);
  }
}

例題

  1. 計算 \(f^{k}(x)\)

    普通做法為多項式快速冪,時間複雜度 \(O(n\log{n}\log{k})\)

    \([x^{0}]f(x)=1\) 時,有:

    \[ f^{k}(x)=\exp{\left(k\ln{f(x)}\right)} \]

    \([x^{0}]f(x)\neq 1\) 時,設 \(f(x)\) 的最低次項為 \(f_{i}x^{i}\),則:

    \[ f^{k}(x)=f_{i}^{k}x^{ik}\exp{\left(k\ln{\frac{f(x)}{f_{i}x^{i}}}\right)} \]

    時間複雜度 \(O(n\log{n})\)

多項式三角函數

給定多項式 \(f\left(x\right)\),求模 \(x^{n}\) 意義下的 \(\sin{f\left(x\right)}, \cos{f\left(x\right)}\)\(\tan{f\left(x\right)}\)

解法

首先由 Euler's formula \(\left(\mathrm{e}^{\mathrm{i}x} = \cos{x} + \mathrm{i}\sin{x}\right)\) 可以得到 三角函數的另一個表達式

\[ \begin{aligned} \sin{x} &= \frac{\mathrm{e}^{\mathrm{i}x} - \mathrm{e}^{-\mathrm{i}x}}{2\mathrm{i}} \\ \cos{x} &= \frac{\mathrm{e}^{\mathrm{i}x} + \mathrm{e}^{-\mathrm{i}x}}{2} \end{aligned} \]

那麼代入 \(f\left(x\right)\) 就有:

\[ \begin{aligned} \sin{f\left(x\right)} &= \frac{\exp{\left(\mathrm{i}f\left(x\right)\right)} - \exp{\left(-\mathrm{i}f\left(x\right)\right)}}{2\mathrm{i}} \\ \cos{f\left(x\right)} &= \frac{\exp{\left(\mathrm{i}f\left(x\right)\right)} + \exp{\left(-\mathrm{i}f\left(x\right)\right)}}{2} \end{aligned} \]

直接按上述表達式編寫程序即可得到模 \(x^{n}\) 意義下的 \(\sin{f\left(x\right)}\)\(\cos{f\left(x\right)}\)。再由 \(\tan{f\left(x\right)} = \frac{\sin{f\left(x\right)}}{\cos{f\left(x\right)}}\) 可求得 \(\tan{f\left(x\right)}\)

代碼

多項式三角函數

注意到我們是在 \(\mathbb{Z}_{998244353}\) 上做 NTT,那麼相應地,虛數單位 \(\mathrm{i}\) 應該被換成 \(86583718\)\(911660635\)

\[ \begin{aligned} & \mathrm{i} = \sqrt{-1} \equiv \sqrt{998244352} \pmod{998244353} \\ \implies & \phantom{\text{or}} \quad \mathrm{i} \equiv 86583718 \pmod{998244353} \\ & \text{or} \quad \mathrm{i} \equiv 911660635 \pmod{998244353} \end{aligned} \]
 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
constexpr int maxn = 262144;
constexpr int mod = 998244353;
constexpr int imgunit = 86583718; /* sqrt(-1) = sqrt(998233452) */

using i64 = long long;
using poly_t = int[maxn];
using poly = int *const;

void polytri(const poly &h, const int n, poly &sin_t, poly &cos_t) {
  /* sin(f) = (exp(i * f) - exp(- i * f)) / 2i */
  /* cos(f) = (exp(i * f) + exp(- i * f)) / 2 */
  /* tan(f) = sin(f) / cos(f) */
  assert(h[0] == 0);
  static poly_t tri1_t, tri2_t;

  for (int i = 0; i != n; ++i) tri2_t[i] = (i64)h[i] * imgunit % mod;
  polyexp(tri2_t, n, tri1_t);
  polyinv(tri1_t, n, tri2_t);

  if (sin_t != nullptr) {
    const int invi = fpow(pls(imgunit, imgunit), mod - 2);
    for (int i = 0; i != n; ++i)
      sin_t[i] = (i64)(tri1_t[i] - tri2_t[i] + mod) * invi % mod;
  }
  if (cos_t != nullptr) {
    for (int i = 0; i != n; ++i) cos_t[i] = div2(pls(tri1_t[i], tri2_t[i]));
  }
}

多項式反三角函數

給定多項式 \(f\left(x\right)\),求模 \(x^{n}\) 意義下的 \(\arcsin{f\left(x\right)}, \arccos{f\left(x\right)}\)\(\arctan{f\left(x\right)}\)

解法

仿照求多項式 \(\ln\) 的方法,對反三角函數求導再積分可得:

\[ \begin{aligned} \frac{\mathrm{d}}{\mathrm{d} x} \arcsin{x} &= \frac{1}{\sqrt{1 - x^{2}}} \\ \arcsin{x} &= \int \frac{1}{\sqrt{1 - x^{2}}} \mathrm{d} x \\ \frac{\mathrm{d}}{\mathrm{d} x} \arccos{x} &= - \frac{1}{\sqrt{1 - x^{2}}} \\ \arccos{x} &= - \int \frac{1}{\sqrt{1 - x^{2}}} \mathrm{d} x \\ \frac{\mathrm{d}}{\mathrm{d} x} \arctan{x} &= \frac{1}{1 + x^{2}} \\ \arctan{x} &= \int \frac{1}{1 + x^{2}} \mathrm{d} x \end{aligned} \]

那麼代入 \(f\left(x\right)\) 就有:

\[ \begin{aligned} \frac{\mathrm{d}}{\mathrm{d} x} \arcsin{f\left(x\right)} &= \frac{f'\left(x\right)}{\sqrt{1 - f^{2}\left(x\right)}} \\ \arcsin{f\left(x\right)} &= \int \frac{f'\left(x\right)}{\sqrt{1 - f^{2}\left(x\right)}} \mathrm{d} x \\ \frac{\mathrm{d}}{\mathrm{d} x} \arccos{f\left(x\right)} &= - \frac{f'\left(x\right)}{\sqrt{1 - f^{2}\left(x\right)}} \\ \arccos{f\left(x\right)} &= - \int \frac{f'\left(x\right)}{\sqrt{1 - f^{2}\left(x\right)}} \mathrm{d} x \\ \frac{\mathrm{d}}{\mathrm{d} x} \arctan{f\left(x\right)} &= \frac{f'\left(x\right)}{1 + f^{2}\left(x\right)} \\ \arctan{f\left(x\right)} &= \int \frac{f'\left(x\right)}{1 + f^{2}\left(x\right)} \mathrm{d} x \end{aligned} \]

直接按式子求就可以了。

代碼

多項式反三角函數
 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
constexpr int maxn = 262144;
constexpr int mod = 998244353;

using i64 = long long;
using poly_t = int[maxn];
using poly = int *const;

void derivative(const poly &h, const int n, poly &f) {
  for (int i = 1; i != n; ++i) f[i - 1] = (i64)h[i] * i % mod;
  f[n - 1] = 0;
}

void integrate(const poly &h, const int n, poly &f) {
  for (int i = n - 1; i; --i) f[i] = (i64)h[i - 1] * inv[i] % mod;
  f[0] = 0; /* C */
}

void polyarcsin(const poly &h, const int n, poly &f) {
  /* arcsin(f) = ∫ f' / sqrt(1 - f^2) dx  */
  static poly_t arcsin_t;
  const int t = n << 1;
  std::copy(h, h + n, arcsin_t);
  std::fill(arcsin_t + n, arcsin_t + t, 0);

  DFT(arcsin_t, t);
  for (int i = 0; i != t; ++i) arcsin_t[i] = sqr(arcsin_t[i]);
  IDFT(arcsin_t, t);

  arcsin_t[0] = sub(1, arcsin_t[0]);
  for (int i = 1; i != n; ++i)
    arcsin_t[i] = arcsin_t[i] ? mod - arcsin_t[i] : 0;

  polysqrt(arcsin_t, n, f);
  polyinv(f, n, arcsin_t);
  derivative(h, n, f);

  DFT(f, t);
  DFT(arcsin_t, t);
  for (int i = 0; i != t; ++i) arcsin_t[i] = (i64)f[i] * arcsin_t[i] % mod;
  IDFT(arcsin_t, t);

  integrate(arcsin_t, n, f);
}

void polyarccos(const poly &h, const int n, poly &f) {
  /* arccos(f) = - ∫ f' / sqrt(1 - f^2) dx  */
  polyarcsin(h, n, f);
  for (int i = 0; i != n; ++i) f[i] = f[i] ? mod - f[i] : 0;
}

void polyarctan(const poly &h, const int n, poly &f) {
  /* arctan(f) = ∫ f' / (1 + f^2) dx  */
  static poly_t arctan_t;
  const int t = n << 1;
  std::copy(h, h + n, arctan_t);
  std::fill(arctan_t + n, arctan_t + t, 0);

  DFT(arctan_t, t);
  for (int i = 0; i != t; ++i) arctan_t[i] = sqr(arctan_t[i]);
  IDFT(arctan_t, t);

  inc(arctan_t[0], 1);
  std::fill(arctan_t + n, arctan_t + t, 0);

  polyinv(arctan_t, n, f);
  derivative(h, n, arctan_t);

  DFT(f, t);
  DFT(arctan_t, t);
  for (int i = 0; i != t; ++i) arctan_t[i] = (i64)f[i] * arctan_t[i] % mod;
  IDFT(arctan_t, t);

  integrate(arctan_t, n, f);
}

參考資料與鏈接