Polynomial Elementary Functions
This page covers common elementary function operations on polynomials. Specifically, it includes:
Polynomial inversion
Polynomial square root
Polynomial division
Polynomial modulo
Polynomial exponential function
Polynomial logarithmic function
Polynomial trigonometric functions
Polynomial inverse trigonometric functions
Elementary and Non-elementary Functions
The definition of elementary functions is as follows :
If there exists a mapping \(u\to \partial u\) on a field \(F\) satisfying:
\(\partial(u+v)=\partial u+\partial v\)
\(\partial(uv)=u\partial v+v\partial u\)
then \(F\) is called a differential field .
A function \(u\) on a differential field \(F\) is called an elementary function if it satisfies any of the following conditions:
\(u\) is an algebraic function over \(F\) .
\(u\) is an exponential function over \(F\) , i.e., there exists \(a\in F\) such that \(\partial u=u\partial a\) .
\(u\) is a logarithmic function over \(F\) , i.e., there exists \(a\in F\) such that \(\partial u=\frac{\partial a}{a}\) .
The following are common elementary functions:
Algebraic functions: functions \(f(x)\) for which there exists a finite-degree polynomial \(P\) such that \(P(f(x))=0\) , e.g., \(2x+1\) , \(\sqrt{x}\) , \((1+x^2)^{-1}\) , \(|x|\) .
Exponential functions
Logarithmic functions
Trigonometric functions
Inverse trigonometric functions
Hyperbolic functions
Inverse hyperbolic functions
Compositions of the above functions, e.g.:
\[
\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)
\]
The following are common non-elementary functions:
Error function:
\[
\operatorname{erf}(x):=\frac{2}{\sqrt{\pi}}\int_{0}^{x}\exp\left(-t^2\right)\mathrm{d}t
\]
Polynomial Inversion
Given a polynomial \(f\left(x\right)\) , find \(f^{-1}\left(x\right)\) .
Solution
Doubling Method
First, it is easy to see that
\[
\left[x^{0}\right]f^{-1}\left(x\right)=\left(\left[x^{0}\right]f\left(x\right)\right)^{-1}
\]
Assume we have already computed the inverse \(f^{-1}_{0}\left(x\right)\) of \(f\left(x\right)\) modulo \(x^{\left\lceil\frac{n}{2}\right\rceil}\) .
We have:
\[
\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}
\]
Squaring both sides gives:
\[
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}}
\]
Multiplying both sides by \(f\left(x\right)\) and rearranging yields:
\[
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}}
\]
Recursively compute this.
Time Complexity
\[
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
Refer to Newton's Method .
Graeffe's Method
To find \(f^{-1}(x)\bmod x^{2n}\) , consider
\[
\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}
\]
We only need to compute \(g^{-1}(x)\bmod x^n\) to recover \(g^{-1}(x^2)\bmod x^{2n}\) because \(f(x)f(-x)\) is an even function. Time complexity is the same as above.
Code
Polynomial Inversion
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 );
}
}
Examples
Counting labeled simple connected undirected graphs: 「POJ 1737」Connected Graph
Polynomial Square Root
Given a polynomial \(g\left(x\right)\) , find \(f\left(x\right)\) such that:
\[
f^{2}\left(x\right)\equiv g\left(x\right) \pmod{x^{n}}
\]
Solution
Doubling Method
First, consider the case where \(\left[x^0\right]g(x)\) is nonzero.
We have:
\[
\left[x^0\right]f(x) = \sqrt{\left[x^0\right]g(x)}
\]
If \(\left[x^0\right]g(x)\) has no square root, then the polynomial \(g(x)\) has no square root.
\(\left[x^0\right]g(x)\) may have multiple square roots; choosing different roots yields different \(f(x)\) .
Assume we have already computed a square root \(f_{0}\left(x\right)\) of \(g\left(x\right)\) modulo \(x^{\left\lceil\frac{n}{2}\right\rceil}\) . Then:
\[
\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}
\]
Compute this via doubling.
Time Complexity
\[
T\left(n\right)=T\left(\frac{n}{2}\right)+O\left(n\log{n}\right)=O\left(n\log{n}\right)
\]
A more constant-friendly approach is to maintain \(f^{-1}\left(x\right)\) alongside \(f\left(x\right)\) during doubling, rather than computing the inverse each time.
When \(\left[x^{0}\right]g\left(x\right)\neq 1\) , quadratic residues may be needed to compute \(\left[x^{0}\right]f\left(x\right)\) .
The above method requires knowing the inverse of \(f_{0}(x)\) , so the constant term cannot be \(0\) .
If \(\left[x^0\right]g(x) = 0\) , factor \(g(x)\) as \(x^{k}h(x)\) , where \(\left[x^0\right]h(x) \not = 0\) .
If \(k\) is odd, then \(g(x)\) has no square root.
If \(k\) is even, compute a square root \(\sqrt{h(x)}\) of \(h(x)\) , then obtain \(f(x) \equiv x^{k/2} \sqrt{h(x)} \pmod{x^{n}}\) .
Luogu Template Problem P5205【Template】Polynomial Square Root Reference Code
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
143 #include <algorithm>
#include <iostream>
using namespace std ;
constexpr int MAXN = 1 << 20 , mod = 998244353 ;
int a [ MAXN ], b [ MAXN ], g [ MAXN ], gg [ MAXN ];
int qpow ( int x , int y ) { // Fast exponentiation
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 ); // Inverse element
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 ) { // Calculate inverse
if ( deg == 1 ) {
h [ 0 ] = qpow ( f [ 0 ], mod - 2 );
return ;
}
inv (( deg + 1 ) >> 1 , f , h );
int len = 1 ;
while ( len < deg * 2 ) { // Doubling
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: degree
// f: array to take square root of
// h: answer array
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 ) { // Doubling
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 ++ ) {
cin >> a [ i ];
}
sqrt ( n , a , b );
for ( int i = 0 ; i < n ; i ++ ) {
cout << b [ i ] << ' ' ;
}
return 0 ;
}
Newton's Method
Refer to Newton's Method .
Examples
「Codeforces Round #250」E. The Child and Binary Tree
Polynomial Division & Modulo
Given polynomials \(f\left(x\right),g\left(x\right)\) , find the quotient \(Q\left(x\right)\) and remainder \(R\left(x\right)\) when dividing \(f\left(x\right)\) by \(g\left(x\right)\) .
Solution
Observe that if we can eliminate the influence of \(R\left(x\right)\) , we can directly use polynomial inversion .
Consider the transformation
\[
f^{R}\left(x\right)=x^{\operatorname{deg}{f}}f\left(\frac{1}{x}\right)
\]
Note that this essentially reverses the coefficients of \(f\left(x\right)\) .
Let \(n=\operatorname{deg}{f},m=\operatorname{deg}{g}\) .
Replace \(x\) with \(\frac{1}{x}\) in \(f\left(x\right)=Q\left(x\right)g\left(x\right)+R\left(x\right)\) and multiply both sides by \(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}
\]
Note that the coefficient of \(R^{R}\left(x\right)\) in the above is \(x^{n-m+1}\) . Thus, working modulo \(x^{n-m+1}\) eliminates the influence of \(R^{R}\left(x\right)\) .
Since the degree of \(Q^{R}\left(x\right)\) is \(\left(n-m\right)<\left(n-m+1\right)\) , \(Q^{R}\left(x\right)\) remains unaffected.
Therefore:
\[
f^{R}\left(x\right)\equiv Q^{R}\left(x\right)g^{R}\left(x\right)\pmod{x^{n-m+1}}
\]
Use polynomial inversion to compute \(Q\left(x\right)\) , then substitute back to obtain \(R\left(x\right)\) .
Time Complexity \(O\left(n\log{n}\right)\) .
Polynomial Logarithmic & Exponential Functions
Given a polynomial \(f(x)\) , compute \(\ln{f(x)}\) and \(\exp{f(x)}\) modulo \(x^{n}\) .
Solution
Standard Method
Polynomial Logarithmic Function Polynomial Exponential Function
First, for a polynomial \(f(x)\) , if \(\ln{f(x)}\) exists, then by its definition , it must satisfy:
\[
[x^{0}]f(x)=1
\]
Differentiating and then integrating \(\ln{f(x)}\) gives:
\[
\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{f(x)} \equiv \int\frac{f'(x)}{f(x)} \mathrm{d} x & \pmod{x^{n}}
\end{aligned}
\]
Polynomial differentiation and integration take \(O(n)\) time, and inversion takes \(O(n\log{n})\) time, so computing the polynomial logarithm takes \(O(n\log{n})\) time.
First, for a polynomial \(f(x)\) , if \(\exp{f(x)}\) exists, then it must satisfy:
\[
[x^{0}]f(x)=0
\]
Otherwise, the constant term of \(\exp{f(x)}\) does not converge.
Differentiating \(\exp{f(x)}\) gives:
\[
\frac{\mathrm{d} \exp{f(x)}}{\mathrm{d} x} \equiv \exp{f(x)}f'(x)\pmod{x^{n}}
\]
Comparing coefficients on both sides yields:
\[
[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)
\]
This can be solved using divide-and-conquer FFT.
Time Complexity \(O(n\log^{2}{n})\) .
Newton's Method
Using Newton's Method , polynomial \(\exp\) can be solved in \(O(n\log{n})\) time.
Code
Polynomial 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 );
}
}
Examples
Compute \(f^{k}(x)\)
The standard method is polynomial fast exponentiation, with time complexity \(O(n\log{n}\log{k})\) .
When \([x^{0}]f(x)=1\) , we have:
\[
f^{k}(x)=\exp{\left(k\ln{f(x)}\right)}
\]
When \([x^{0}]f(x)\neq 1\) , let the lowest-degree term of \(f(x)\) be \(f_{i}x^{i}\) . Then:
\[
f^{k}(x)=f_{i}^{k}x^{ik}\exp{\left(k\ln{\frac{f(x)}{f_{i}x^{i}}}\right)}
\]
Time Complexity \(O(n\log{n})\) .
Polynomial Trigonometric Functions
Given a polynomial \(f\left(x\right)\) , compute \(\sin{f\left(x\right)}, \cos{f\left(x\right)}\) , and \(\tan{f\left(x\right)}\) modulo \(x^{n}\) .
Solution
First, from Euler's formula \(\left(\mathrm{e}^{\mathrm{i}x} = \cos{x} + \mathrm{i}\sin{x}\right)\) , we obtain another expression for trigonometric functions :
\[
\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}
\]
Substituting \(f\left(x\right)\) gives:
\[
\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}
\]
Directly implementing the above expressions yields \(\sin{f\left(x\right)}\) and \(\cos{f\left(x\right)}\) modulo \(x^{n}\) . Then \(\tan{f\left(x\right)} = \frac{\sin{f\left(x\right)}}{\cos{f\left(x\right)}}\) gives \(\tan{f\left(x\right)}\) .
Code
Polynomial Trigonometric Functions
Note that we are performing NTT over \(\mathbb{Z}_{998244353}\) , so the imaginary unit \(\mathrm{i}\) should be replaced by \(86583718\) or \(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 ]));
}
}
Polynomial Inverse Trigonometric Functions
Given a polynomial \(f\left(x\right)\) , compute \(\arcsin{f\left(x\right)}, \arccos{f\left(x\right)}\) , and \(\arctan{f\left(x\right)}\) modulo \(x^{n}\) .
Solution
Following the method for polynomial \(\ln\) , differentiate and then integrate the inverse trigonometric functions:
\[
\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}
\]
Substituting \(f\left(x\right)\) gives:
\[
\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}
\]
Compute directly using these formulas.
Code
Polynomial Inverse Trigonometric Functions
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 );
}
References and Links
本页面最近更新: ,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:OI-wiki
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用