多项式操作公式记录
多项式操作公式记录
不证明了。
以下默认 为 次多项式 ,且 为 的整数幂。
快速傅里叶变换/数论变换
其中 ,,。 代表最小的 次单位根/原根。
求乘法逆
其中 代表 的前 项;。
注意: 不一定是 乘法逆的前 项,它只是 前 项的乘法逆。
求对数函数
有
则
求导、积分公式:
其中 是常数。对于多项式,二者均是线性可加的。
求指数函数
有递推式
其中下标代表多项式的前几项。
递归求解即可。
多项式 次幂
多项式开根
即多项式 次幂。
封装代码
namespace Poly {
const int G = 3;
const int MOD = 998244353;
const int PHI = 998244352;
const int DPHI = 998244351;
const int SzI = sizeof(int);
const int SzL = sizeof(long long int);
void Init(int *const A, const int N) {
for (int i = 0; i < N; ++i) {
qr(A[i]);
}
}
void Print(const int *const A, const int N) {
int DN = N - 1;
for (int i = 0; i < DN; ++i) {
qw(A[i], ' ', true);
}
qw(A[DN], '\n', true);
}
void GetN(int n, int &N) {
N = 1;
while (N < n) N <<= 1;
}
int mpow(int x, int y) {
int _ret = 1;
while (y) {
if (y & 1) _ret = 1ll * x * _ret % MOD;
x = 1ll * x * x % MOD;
y >>= 1;
}
return _ret;
}
int tax[maxn], taxlen;
void GetRev(const int N) {
int p = 1, d = N >> 1;
for (int w = p; w < N; w = p) {
for (int i = 0; i < w; ++i) {
tax[p++] = tax[i] | d;
}
d >>= 1;
}
taxlen = N;
}
void MakeRev(int *const A, const int N) {
for (int i = 1; i < N; ++i) if (tax[i] > i) {
std::swap(A[i], A[tax[i]]);
}
}
void Modint(int &x) {
while (x >= MOD) x -= MOD;
while (x < 0) x += MOD;
}
void NTT(int *const A, const int N) {
if (taxlen != N) {
GetRev(N);
}
MakeRev(A, N);
for (int w = 2, M = 1; w <= N; w <<= 1) {
int Wn = mpow(G, PHI / w);
for (int L = 0; L < N; L += w) {
ll g = 1;
for (int i = L, lm = L + M, j = lm; i < lm; ++i, ++j) {
ll x = A[i], y = A[j];
A[i] = (x + g * y) % MOD; A[j] = (x - g * y) % MOD;
(g *= Wn) %= MOD;
}
}
M = w;
}
for (int i = 0; i < N; ++i) {
Modint(A[i]);
}
}
void GetInv(const int *const A, int *const B, const int N) {
static int C[maxn];
B[0] = mpow(A[0], DPHI);
for (int w = 2, M = 4; w <= N; M <<= 1) {
memcpy(C, A, w * SzI);
NTT(B, M); NTT(C, M);
for (int i = 0; i < M; ++i) {
B[i] = (B[i] << 1) % MOD - 1ll * C[i] * B[i] % MOD * B[i] % MOD;
Modint(B[i]);
}
NTT(B, M);
std::reverse(B + 1, B + M);
for (int i = 0, iv = mpow(M, DPHI); i < w; ++i) {
B[i] = 1ll * B[i] * iv % MOD;
}
memset(B + w, 0, w * SzI);
w = M;
}
memset(C, 0, (N << 1) * SzI);
}
void GetDer(const int *const A, int *const B, const int N) {
for (int i = 1; i < N; ++i) {
B[i - 1] = 1ll * A[i] * i % MOD;
}
B[N - 1] = 0;
}
void GetInte(const int *const A, int *const B, const int N) {
B[0] = 0;
for (int i = 1; i < N; ++i) {
B[i] = 1ll * A[i - 1] * mpow(i, DPHI) % MOD;
}
}
void GetLn(const int *const A, int *const B, const int N) {
static int C[maxn];
GetDer(A, B, N);
GetInv(A, C, N);
int M = N << 1;
NTT(B, M); NTT(C, M);
for (int i = 0; i < M; ++i) {
C[i] = 1ll * B[i] * C[i] % MOD;
}
NTT(C, M);
std::reverse(C + 1, C + M);
for (int i = 0, iv = mpow(M, DPHI); i < N; ++i) {
C[i] = 1ll * C[i] * iv % MOD;
}
GetInte(C, B, N);
memset(B + N, 0, N * SzI);
memset(C, 0, M * SzI);
}
void GetExp(const int *const A, int *const B, const int N) {
static int C[maxn];
if (N == 1) {
B[0] = 1;
return;
}
GetExp(A, B, N >> 1);
GetLn(B, C, N);
int M = N << 1;
for (int i = 0; i < N; ++i) {
C[i] = -C[i] + A[i];
Modint(C[i]);
}
C[0] += 1;
NTT(C, M); NTT(B, M);
for (int i = 0; i < M; ++i) {
B[i] = 1ll * B[i] * C[i] % MOD;
}
NTT(B, M);
std::reverse(B + 1, B + M);
for (int i = 0, iv = mpow(M, DPHI); i < N; ++i) {
B[i] = 1ll * B[i] * iv % MOD;
}
memset(B + N, 0, N * SzI);
memset(C, 0, M * SzI);
}
void GetPow(const int *const A, const int k, int *const B, const int N) {
static int C[maxn];
GetLn(A, C, N);
for (int i = 0; i < N; ++i) {
C[i] = 1ll * C[i] * k % MOD;
}
GetExp(C, B, N);
memset(C, 0, N * SzI);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
2019-01-06 【DP】【CF1097D】 Makoto and a Blackboard