多项式全集
Code
#pragma GCC optimize(2, "inline", "Ofast")
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 500;
const int Md = 998244353;
typedef long long ll;
typedef vector<int> Vec;
namespace {
inline int Add(const int &x, const int &y) {return (x + y >= Md) ? (x + y - Md) : (x + y);}
inline int Sub(const int &x, const int &y) {return (x - y < 0) ? (x - y + Md) :(x - y);}
inline int Mul(const int &x, const int &y) {return (ll)x * y % Md;}
int Powe(int x, int y) {
int ans = 1;
while(y) {
if(y & 1) ans = Mul(ans, x);
x = Mul(x, x);
y >>= 1;
}
return ans;
}
}
void read(int &x) {
x = 0; int f = 1; char ch = getchar();
while(ch > '9' || ch < '0') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();}
x *= f;
}
int n, m, a, b;
namespace Poly {
int rev[N << 2 | 1], inv[N];
int Iv2;
void Init() {
inv[0]=0; inv[1]=1;
for(int i = 2; i < N; i++) {
inv[i] = ((ll)(Md - Md / i) * inv[Md % i]) % Md;
}
Iv2 = Powe(2, Md - 2);
}
void DFT(Vec &A, int len) {
for(int i = 0; i < len; i++) if(i < rev[i]) swap(A[i], A[rev[i]]);
for(int i = 1; i < len; i <<= 1) {
int wn = Powe(3, (Md - 1) / (i << 1));
for(int j = 0; j < len; j += i << 1) {
int nw = 1, x, y;
for(int k = 0; k < i; k++, nw = Mul(nw, wn)) {
x = A[j + k], y = Mul(nw, A[i + j + k]);
A[j + k] = Add(x, y); A[i + j + k] = Sub(x, y);
}
}
}
}
void IDFT(Vec &A, int len) {
reverse(A.begin() + 1, A.end());
int Iv = Powe(len, Md - 2);
DFT(A, len);
for(int i = 0; i < len; i++) A[i] = Mul(A[i], Iv);
}
Vec MUL(Vec A, Vec B) {
int n = A.size(), m = B.size(), len;
for(len = 1; len < n + m - 1; len <<= 1);
A.resize(len), B.resize(len);
for(int i = 0; i < len; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? len >> 1 : 0);
DFT(A, len), DFT(B, len);
for(int i = 0; i < len; i++) A[i] = Mul(A[i], B[i]);
IDFT(A, len);
A.resize(n + m - 1);
return A;
}
Vec GetInv(Vec A, int len) {
Vec C, B(1, Powe(A[0], Md - 2));
for(int i = 2; (i >> 1) < len; i <<= 1) {
for(int j = 0; j < (i << 1); j++) rev[j] = (rev[j >> 1] >> 1) | ((j & 1) ? i : 0);
C = A; C.resize(i);
C.resize(i << 1); DFT(C, i << 1);
B.resize(i << 1); DFT(B, i << 1);
for(int j = 0; j < (i << 1); j++) B[j] = Mul(B[j], Sub(2, Mul(C[j], B[j])));
IDFT(B, i << 1);
B.resize(i);
}
B.resize(len);
return B;
}
void GetDiv(Vec A, Vec B, Vec &Q, Vec &R) {
Q.resize(n + 1); Vec Gr; Gr.clear(); Gr.resize(m + 1);
for(int i = 0; i <= n; i++) Q[i] = A[n - i];
for(int i = 0; i <= m; i++) Gr[i] = B[m - i];
for(int i = n - m + 2; i <= m; i++) Gr[i] = 0;
Vec Iv; Iv.clear();
Gr.resize(n - m + 1); Iv.resize(n - m + 1);
Iv = GetInv(Gr, n - m + 1);
Q = MUL(Q, Iv);
Q.resize(n - m + 1);
reverse(Q.begin(), Q.end());
for(int i = n - m + 1; i <= n; i++) Q[i] = 0;
R = MUL(Q, B);
for(int i = 0; i <= m - 1; i++) R[i] = Add(A[i], Sub(Md, R[i]));
}
Vec Dir(Vec A) {
Vec B = A; int len = A.size(); B.resize(len);
for(int i = 1; i < len; i++) B[i - 1] = Mul(A[i], i);
B[len - 1] = 0;
return B;
}
Vec Inter(Vec A) {
Vec B = A; int len = A.size(); B.resize(len);
for(int i = 1; i < len; i++) B[i] = Mul(A[i - 1], inv[i]);
B[0] = 0;
return B;
}
Vec Ln(Vec A, int len) {
A = Inter(MUL(Dir(A), GetInv(A, len)));
A.resize(len);
return A;
}
Vec Exp(Vec A, int len) {
Vec B(1, 1), F;
for(int i = 2; (i >> 1) < len; i <<= 1) {
if((int)A.size() < i) A.resize(i);
F = Ln(B, i);
for(int j = 0; j < i; j++) F[j] = Sub(A[j], F[j]);
F[0] = Add(F[0], 1);
B = MUL(B, F);
B.resize(i);
}
B.resize(len);
return B;
}
Vec Powe(Vec A, int len, int k) {
k %= Md;
int x = ::Powe(A[0], Md - 2);
int y = ::Powe(A[0], k);
Vec B = A;
for(int i = 0; i < len; i++) B[i] = Mul(B[i], x);
B = Ln(B, len);
for(int i = 0; i < len; i++) B[i] = Mul(B[i], k);
B = Exp(B, len);
for(int i = 0; i < len; i++) B[i] = Mul(B[i], y);
return B;
}
Vec Sqrt(Vec A, int len) {
assert(A[0] == 4);
Vec C, D, B(1, 2);
for (int i = 2; (i >> 1) < len; i <<= 1) {
C = A, C.resize(i);
D = GetInv(B, i);
C = MUL(C, D);
B.resize(i);
for (int j = 0; j < i; j++) B[j] = Mul(Add(C[j], B[j]), Iv2);
}
B.resize(len);
return B;
}
}
int main() {
Poly::Init();
return 0;
}