牛顿迭代
快速多项式计算
加法
\(H(x) = F(x) + G(x)\),求\(H(x)\)
解:都已经\(O(n)\)了,还怎么优化!!!
乘法
\(H(x) \equiv F(x)G(x) (\text{mod }x^n)\),求\(H(x)\)
完整代码:P3803 【模板】多项式乘法(FFT)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e6 + 9, MOD = 998244353;
int rev[N];
int qpow(int x, int y){
int res = 1;
while(y){
if(y & 1)
res = res * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return res;
}
void NTT(int *f, int n, int opt){
for(int i = 0; i < n; i++){
rev[i] = rev[i >> 1] >> 1;
if(i % 2 == 1)
rev[i] |= n >> 1;
}
for(int i = 0; i < n; i++)
if(i < rev[i])
swap(f[i], f[rev[i]]);
for(int h = 2; h <= n; h <<= 1){
int mi = h >> 1;
int gn = qpow(3, (MOD - 1) / h);
for(int j = 0; j < n; j += h){
int g = 1;
for(int k = 0; k < mi; k++){
int tmp = f[j + k + mi] * g % MOD;
f[j + k + mi] = (f[j + k] - tmp + MOD) % MOD;
f[j + k] = (f[j + k] + tmp) % MOD;
g = g * gn % MOD;
}
}
}
if(opt == -1){
reverse(f + 1, f + n);
int inv = qpow(n, MOD - 2);
for(int i = 0; i < n; i++)
f[i] = f[i] * inv % MOD;
}
}
int f[N << 1], g[N << 1], n, m;
signed main(){
scanf("%lld%lld", &n, &m);
for(int i = 0; i <= n; i++)
scanf("%lld", &f[i]);
for(int i = 0; i <= m; i++)
scanf("%lld", &g[i]);
int lim = 1;
while(lim <= n + m)
lim <<= 1;
NTT(f, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i <= lim; i++)
f[i] = f[i] * g[i] % MOD;
NTT(f, lim, -1);
for(int i = 0; i <= n + m; i++)
printf("%lld ", f[i]);
return 0;
}
求逆
\(F(x)G(x) \equiv 1 (\text{mod }x^n)\)
求\(G(x)\)
解:
完整代码:P4238 【模板】多项式乘法逆
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e6 + 9, MOD = 998244353;
int rev[N];
int qpow(int x, int y){
int res = 1;
while(y){
if(y & 1)
res = res * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return res;
}
void NTT(int *f, int n, int opt){
for(int i = 0; i < n; i++){
rev[i] = rev[i >> 1] >> 1;
if(i % 2 == 1)
rev[i] |= n >> 1;
}
for(int i = 0; i < n; i++)
if(i < rev[i])
swap(f[i], f[rev[i]]);
for(int h = 2; h <= n; h <<= 1){
int mi = h >> 1;
int gn = qpow(3, (MOD - 1) / h);
for(int j = 0; j < n; j += h){
int g = 1;
for(int k = 0; k < mi; k++){
int tmp = f[j + k + mi] * g % MOD;
f[j + k + mi] = (f[j + k] - tmp + MOD) % MOD;
f[j + k] = (f[j + k] + tmp) % MOD;
g = g * gn % MOD;
}
}
}
if(opt == -1){
reverse(f + 1, f + n);
int inv = qpow(n, MOD - 2);
for(int i = 0; i < n; i++)
f[i] = f[i] * inv % MOD;
}
}
int tmp[N << 1];
void solve(int *f, int *g, int n){
if(!n){
g[0] = qpow(f[0], MOD - 2);
return;
}
solve(f, g, n >> 1);
int lim = 1;
while(lim <= n * 2 + 1)
lim <<= 1;
for(int i = 0; i <= n; i++)
tmp[i] = f[i];
NTT(tmp, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = (2 - g[i] * tmp[i] % MOD + MOD) % MOD * g[i] % MOD;
NTT(g, lim, -1);
for(int i = n + 1; i < lim; i++)
g[i] = 0;
}
int f[N << 1], g[N << 1], n;
signed main(){
scanf("%lld", &n);
n--;
for(int i = 0; i <= n; i++)
scanf("%lld", &f[i]);
solve(f, g, n);
for(int i = 0; i <= n; i++)
printf("%lld ", g[i]);
return 0;
}
除法/取模
\(F(x)\equiv Q(x)G(x)+R(x)(\text{mod }{x^n})\)
求\(Q(x),R(x)\)
解:
完整代码:P4512 【模板】多项式除法
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e6 + 9, MOD = 998244353;
int rev[N];
int qpow(int x, int y){
int res = 1;
while(y){
if(y & 1)
res = res * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return res;
}
void NTT(int *f, int n, int opt){
for(int i = 0; i < n; i++){
rev[i] = rev[i >> 1] >> 1;
if(i % 2 == 1)
rev[i] |= n >> 1;
}
for(int i = 0; i < n; i++)
if(i < rev[i])
swap(f[i], f[rev[i]]);
for(int h = 2; h <= n; h <<= 1){
int mi = h >> 1;
int gn = qpow(3, (MOD - 1) / h);
for(int j = 0; j < n; j += h){
int g = 1;
for(int k = 0; k < mi; k++){
int tmp = f[j + k + mi] * g % MOD;
f[j + k + mi] = (f[j + k] - tmp + MOD) % MOD;
f[j + k] = (f[j + k] + tmp) % MOD;
g = g * gn % MOD;
}
}
}
if(opt == -1){
reverse(f + 1, f + n);
int inv = qpow(n, MOD - 2);
for(int i = 0; i < n; i++)
f[i] = f[i] * inv % MOD;
}
}
int tmp[N << 1];
void inv(int *f, int *g, int n){
if(!n){
g[0] = qpow(f[0], MOD - 2);
return;
}
inv(f, g, n >> 1);
int lim = 1;
while(lim <= n * 2 + 1)
lim <<= 1;
for(int i = 0; i <= n; i++)
tmp[i] = f[i];
NTT(tmp, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = (2 - g[i] * tmp[i] % MOD + MOD) % MOD * g[i] % MOD;
NTT(g, lim, -1);
for(int i = n + 1; i < lim; i++)
g[i] = 0;
}
void div(int *f, int *g, int len1, int len2){
int lim = 1;
while(lim <= len1 + len2)
lim <<= 1;
NTT(f, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i <= lim; i++)
f[i] = f[i] * g[i] % MOD;
NTT(f, lim, -1);
}
int f[N << 1], g[N << 1], r[N << 1], q[N << 1], rf[N << 1], rg[N << 1], rr[N << 1], n, m;
signed main(){
scanf("%lld%lld", &n, &m);
for(int i = 0; i <= n; i++){
scanf("%lld", &f[i]);
rf[n - i] = f[i];
}
for(int i = 0; i <= m; i++){
scanf("%lld", &g[i]);
rg[m - i] = g[i];
}
for(int i = n - m + 1; i <= m; i++)
rg[i] = 0;
inv(rg, rr, n - m);
div(rf, rr, n, n - m);
for(int i = 0; i <= n - m; i++)
printf("%lld ", q[i] = rf[n - m - i]);
printf("\n");
div(g, q, m, n - m);
for(int i = 0; i < m; i++)
printf("%lld ", r[i] = (f[i] - g[i] + MOD) % MOD);
return 0;
}
求导/积分
\(G(x) = F'(x)\)
\(H(x) = \displaystyle\int F(x)dx\)
求\(G(x),H(x)\)
解:都已经\(O(n)\)了,还怎么优化!!!
完整代码:U455122 【模板】多项式求导/积分
开根
\(G^2(x) \equiv F(x)(\text{mod }{x^n})\)
求\(G(x)\)
解:
完整代码:P5205 【模板】多项式开根
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 9, MOD = 998244353;
int rev[N], in[N];
void init(){
in[1] = 1;
for(int i = 2; i <= N; i++)
in[i] = (MOD - MOD / i) * in[MOD % i] % MOD;
}
int qpow(int x, int y){
int res = 1;
while(y){
if(y & 1)
res = res * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return res;
}
void NTT(int *f, int n, int opt){
for(int i = 0; i < n; i++){
rev[i] = rev[i >> 1] >> 1;
if(i % 2 == 1)
rev[i] |= n >> 1;
}
for(int i = 0; i < n; i++)
if(i < rev[i])
swap(f[i], f[rev[i]]);
for(int h = 2; h <= n; h <<= 1){
int mi = h >> 1;
int gn = qpow(3, (MOD - 1) / h);
for(int j = 0; j < n; j += h){
int g = 1;
for(int k = 0; k < mi; k++){
int tmp = f[j + k + mi] * g % MOD;
f[j + k + mi] = (f[j + k] - tmp + MOD) % MOD;
f[j + k] = (f[j + k] + tmp) % MOD;
g = g * gn % MOD;
}
}
}
if(opt == -1){
reverse(f + 1, f + n);
int inv = qpow(n, MOD - 2);
for(int i = 0; i < n; i++)
f[i] = f[i] * inv % MOD;
}
}
int tmp[N << 1];
void inv(int *f, int *g, int n){
if(!n){
g[0] = qpow(f[0], MOD - 2);
return;
}
inv(f, g, n >> 1);
int lim = 1;
while(lim < 2 * n + 1)
lim <<= 1;
for(int i = 0; i <= n; i++)
tmp[i] = f[i];
for(int i = n + 1; i < lim; i++)
tmp[i] = 0;
NTT(tmp, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = (2 - g[i] * tmp[i] % MOD + MOD) % MOD * g[i] % MOD;
NTT(g, lim, -1);
for(int i = n + 1; i < lim; i++)
g[i] = 0;
}
int f2[N << 1];
void ln(int *f, int *g, int n){
for(int i = 0; i < n * 4 + 3; i++)
g[i] = 0;
inv(f, g, n);
int lim = 1;
while(lim < 2 * n + 1)
lim <<= 1;
for(int i = 0; i < n; i++)
f2[i] = f[i + 1] * (i + 1) % MOD;
for(int i = n; i < lim; i++)
f2[i] = 0;
NTT(f2, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = g[i] * f2[i] % MOD;
NTT(g, lim, -1);
for(int i = n; i > 0; i--)
g[i] = g[i - 1] * in[i] % MOD;
for(int i = n + 1; i < lim; i++)
g[i] = 0;
g[0] = 0;
}
int lng[N << 1];
void exp(int *f, int *g, int n){
if(!n){
g[0] = 1;
return;
}
exp(f, g, n >> 1);
ln(g, lng, n);
int lim = 1;
while(lim < 2 * n + 1)
lim <<= 1;
for(int i = 0; i <= n; i++){
if(f[i] >= lng[i])
lng[i] = f[i] - lng[i];
else
lng[i] = f[i] - lng[i] + MOD;
}
for(int i = n + 1; i < lim; i++)
lng[i] = g[i] = 0;
lng[0]++;
NTT(lng, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = g[i] * lng[i] % MOD;
NTT(g, lim, -1);
for(int i = n + 1; i < lim; i++)
g[i] = 0;
}
int f[N << 1], g[N << 1], res[N << 1], n, k;
char s[1009];
signed main(){
init();
scanf("%lld", &n);
n--;
for(int i = 0; i <= n; i++)
scanf("%lld", &f[i]);
ln(f, g, n);
int inv = qpow(2, MOD - 2);
for(int i = 0; i <= n; i++)
g[i] = g[i] * inv % MOD;
exp(g, res, n);
for(int i = 0; i <= n; i++)
printf("%lld ", res[i]);
return 0;
}
对数函数
\(G(x) \equiv \text{ln }F(x)(\text{mod } x^n)\),保证\(f_0 = 1\)
求\(G(x)\)
解:
完整代码:P4725 【模板】多项式对数函数(多项式 ln)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e6 + 9, MOD = 998244353;
int rev[N], in[N];
void init(){
in[1] = 1;
for(int i = 2; i <= N; i++)
in[i] = (MOD - MOD / i) * in[MOD % i] % MOD;
}
int qpow(int x, int y){
int res = 1;
while(y){
if(y & 1)
res = res * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return res;
}
void NTT(int *f, int n, int opt){
for(int i = 0; i < n; i++){
rev[i] = rev[i >> 1] >> 1;
if(i % 2 == 1)
rev[i] |= n >> 1;
}
for(int i = 0; i < n; i++)
if(i < rev[i])
swap(f[i], f[rev[i]]);
for(int h = 2; h <= n; h <<= 1){
int mi = h >> 1;
int gn = qpow(3, (MOD - 1) / h);
for(int j = 0; j < n; j += h){
int g = 1;
for(int k = 0; k < mi; k++){
int tmp = f[j + k + mi] * g % MOD;
f[j + k + mi] = (f[j + k] - tmp + MOD) % MOD;
f[j + k] = (f[j + k] + tmp) % MOD;
g = g * gn % MOD;
}
}
}
if(opt == -1){
reverse(f + 1, f + n);
int inv = qpow(n, MOD - 2);
for(int i = 0; i < n; i++)
f[i] = f[i] * inv % MOD;
}
}
int tmp[N << 1];
void inv(int *f, int *g, int n){
if(!n){
g[0] = qpow(f[0], MOD - 2);
return;
}
inv(f, g, n >> 1);
int lim = 1;
while(lim <= n * 2 + 1)
lim <<= 1;
for(int i = 0; i <= n; i++)
tmp[i] = f[i];
NTT(tmp, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = (2 - g[i] * tmp[i] % MOD + MOD) % MOD * g[i] % MOD;
NTT(g, lim, -1);
for(int i = n + 1; i < lim; i++)
g[i] = 0;
}
int f2[N << 1];
void ln(int *f, int *g, int n){
inv(f, g, n);
int lim = 1;
while(lim <= n * 2 + 1)
lim <<= 1;
for(int i = 0; i < n; i++)
f2[i] = f[i + 1] * (i + 1) % MOD;
for(int i = n; i < lim; i++)
f2[i] = 0;
NTT(f2, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = g[i] * f2[i] % MOD;
NTT(g, lim, -1);
for(int i = n; i > 0; i--)
g[i] = g[i - 1] * in[i] % MOD;
for(int i = n + 1; i < lim; i++)
g[i] = 0;
g[0] = 0;
}
int f[N << 1], g[N << 1], n;
signed main(){
init();
scanf("%lld", &n);
n--;
for(int i = 0; i <= n; i++)
scanf("%lld", &f[i]);
ln(f, g, n);
for(int i = 0; i <= n; i++)
printf("%lld ", g[i]);
return 0;
}
指数函数
\(G(x) \equiv e^{F(x)}(\text{mod } x^n)\),保证\(f_0 = 0\)
求:\(G(x)\)
解:
完整代码:P4726 【模板】多项式指数函数(多项式 exp)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e6 + 9, MOD = 998244353;
int rev[N], in[N];
void init(){
in[1] = 1;
for(int i = 2; i <= N; i++)
in[i] = (MOD - MOD / i) * in[MOD % i] % MOD;
}
int qpow(int x, int y){
int res = 1;
while(y){
if(y & 1)
res = res * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return res;
}
void NTT(int *f, int n, int opt){
for(int i = 0; i < n; i++){
rev[i] = rev[i >> 1] >> 1;
if(i % 2 == 1)
rev[i] |= n >> 1;
}
for(int i = 0; i < n; i++)
if(i < rev[i])
swap(f[i], f[rev[i]]);
for(int h = 2; h <= n; h <<= 1){
int mi = h >> 1;
int gn = qpow(3, (MOD - 1) / h);
for(int j = 0; j < n; j += h){
int g = 1;
for(int k = 0; k < mi; k++){
int tmp = f[j + k + mi] * g % MOD;
f[j + k + mi] = (f[j + k] - tmp + MOD) % MOD;
f[j + k] = (f[j + k] + tmp) % MOD;
g = g * gn % MOD;
}
}
}
if(opt == -1){
reverse(f + 1, f + n);
int inv = qpow(n, MOD - 2);
for(int i = 0; i < n; i++)
f[i] = f[i] * inv % MOD;
}
}
int tmp[N << 1];
void inv(int *f, int *g, int n){
if(!n){
g[0] = qpow(f[0], MOD - 2);
return;
}
inv(f, g, n >> 1);
int lim = 1;
while(lim < 2 * n + 1)
lim <<= 1;
for(int i = 0; i <= n; i++)
tmp[i] = f[i];
for(int i = n + 1; i < lim; i++)
tmp[i] = 0;
NTT(tmp, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = (2 - g[i] * tmp[i] % MOD + MOD) % MOD * g[i] % MOD;
NTT(g, lim, -1);
for(int i = n + 1; i < lim; i++)
g[i] = 0;
}
int f2[N << 1];
void ln(int *f, int *g, int n){
for(int i = 0; i < n * 4 + 3; i++)
g[i] = 0;
inv(f, g, n);
int lim = 1;
while(lim < 2 * n + 1)
lim <<= 1;
for(int i = 0; i < n; i++)
f2[i] = f[i + 1] * (i + 1) % MOD;
for(int i = n; i < lim; i++)
f2[i] = 0;
NTT(f2, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = g[i] * f2[i] % MOD;
NTT(g, lim, -1);
for(int i = n; i > 0; i--)
g[i] = g[i - 1] * in[i] % MOD;
for(int i = n + 1; i < lim; i++)
g[i] = 0;
g[0] = 0;
}
int lng[N << 1];
void exp(int *f, int *g, int n){
if(!n){
g[0] = 1;
return;
}
exp(f, g, n >> 1);
ln(g, lng, n);
int lim = 1;
while(lim < 2 * n + 1)
lim <<= 1;
for(int i = 0; i <= n; i++){
if(f[i] >= lng[i])
lng[i] = f[i] - lng[i];
else
lng[i] = f[i] - lng[i] + MOD;
}
for(int i = n + 1; i < lim; i++)
lng[i] = g[i] = 0;
lng[0]++;
NTT(lng, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = g[i] * lng[i] % MOD;
NTT(g, lim, -1);
for(int i = n + 1; i < lim; i++)
g[i] = 0;
}
int f[N << 1], g[N << 1], n;
signed main(){
init();
scanf("%lld", &n);
n--;
for(int i = 0; i <= n; i++)
scanf("%lld", &f[i]);
exp(f, g, n);
for(int i = 0; i <= n; i++)
printf("%lld ", g[i]);
return 0;
}
幂函数
\(G(x) \equiv F^k(x)(\text{mod } x ^ n)\)
求\(G(x)\)
解:
完整代码:P5245 【模板】多项式快速幂
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5e6 + 9, MOD = 998244353;
int rev[N], in[N];
void init(){
in[1] = 1;
for(int i = 2; i <= N; i++)
in[i] = (MOD - MOD / i) * in[MOD % i] % MOD;
}
int qpow(int x, int y){
int res = 1;
while(y){
if(y & 1)
res = res * x % MOD;
x = x * x % MOD;
y >>= 1;
}
return res;
}
void NTT(int *f, int n, int opt){
for(int i = 0; i < n; i++){
rev[i] = rev[i >> 1] >> 1;
if(i % 2 == 1)
rev[i] |= n >> 1;
}
for(int i = 0; i < n; i++)
if(i < rev[i])
swap(f[i], f[rev[i]]);
for(int h = 2; h <= n; h <<= 1){
int mi = h >> 1;
int gn = qpow(3, (MOD - 1) / h);
for(int j = 0; j < n; j += h){
int g = 1;
for(int k = 0; k < mi; k++){
int tmp = f[j + k + mi] * g % MOD;
f[j + k + mi] = (f[j + k] - tmp + MOD) % MOD;
f[j + k] = (f[j + k] + tmp) % MOD;
g = g * gn % MOD;
}
}
}
if(opt == -1){
reverse(f + 1, f + n);
int inv = qpow(n, MOD - 2);
for(int i = 0; i < n; i++)
f[i] = f[i] * inv % MOD;
}
}
int tmp[N << 1];
void inv(int *f, int *g, int n){
if(!n){
g[0] = qpow(f[0], MOD - 2);
return;
}
inv(f, g, n >> 1);
int lim = 1;
while(lim < 2 * n + 1)
lim <<= 1;
for(int i = 0; i <= n; i++)
tmp[i] = f[i];
for(int i = n + 1; i < lim; i++)
tmp[i] = 0;
NTT(tmp, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = (2 - g[i] * tmp[i] % MOD + MOD) % MOD * g[i] % MOD;
NTT(g, lim, -1);
for(int i = n + 1; i < lim; i++)
g[i] = 0;
}
int f2[N << 1];
void ln(int *f, int *g, int n){
for(int i = 0; i < n * 4 + 3; i++)
g[i] = 0;
inv(f, g, n);
int lim = 1;
while(lim < 2 * n + 1)
lim <<= 1;
for(int i = 0; i < n; i++)
f2[i] = f[i + 1] * (i + 1) % MOD;
for(int i = n; i < lim; i++)
f2[i] = 0;
NTT(f2, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = g[i] * f2[i] % MOD;
NTT(g, lim, -1);
for(int i = n; i > 0; i--)
g[i] = g[i - 1] * in[i] % MOD;
for(int i = n + 1; i < lim; i++)
g[i] = 0;
g[0] = 0;
}
int lng[N << 1];
void exp(int *f, int *g, int n){
if(!n){
g[0] = 1;
return;
}
exp(f, g, n >> 1);
ln(g, lng, n);
int lim = 1;
while(lim < 2 * n + 1)
lim <<= 1;
for(int i = 0; i <= n; i++){
if(f[i] >= lng[i])
lng[i] = f[i] - lng[i];
else
lng[i] = f[i] - lng[i] + MOD;
}
for(int i = n + 1; i < lim; i++)
lng[i] = g[i] = 0;
lng[0]++;
NTT(lng, lim, 1);
NTT(g, lim, 1);
for(int i = 0; i < lim; i++)
g[i] = g[i] * lng[i] % MOD;
NTT(g, lim, -1);
for(int i = n + 1; i < lim; i++)
g[i] = 0;
}
int f[N << 1], g[N << 1], res[N << 1], n, k;
char s[10000009];
signed main(){
init();
scanf("%lld%s", &n, s + 1);
n--;
int len = strlen(s + 1);
for(int i = 1; i <= len; i++)
k = ((k << 3) + (k << 1) + (s[i] - 48)) % MOD;
for(int i = 0; i <= n; i++)
scanf("%lld", &f[i]);
ln(f, g, n);
for(int i = 0; i <= n; i++)
g[i] = g[i] * k % MOD;
exp(g, res, n);
for(int i = 0; i <= n; i++)
printf("%lld ", res[i]);
return 0;
}
三角函数
\(G(x) = \text{sin }F(x)\)
\(H(x) = \text{cos }F(x)\)
求\(G(x),H(x)\)
解:
完整代码:P5264 多项式三角函数