初三多项式的运算练习 题解
美好的下午时光要拿来写题解呜呜呜,一篇一篇地鸽得了。
有些题要用到 GF 的知识,或许我可以找时间讲一下?
贴一份我的 FFT 和 NTT 的板子。
FFT:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n, m, limit, f[1 << 22], g[1 << 22], h[1 << 22];
namespace poly {
typedef complex<double> cplx;
const double pi = acos(-1.0);
void FFT(cplx *f, int limit, double type) {
static int r[1 << 22];
for(int i = 1, l = __lg(limit); i < limit; ++i) {
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
if(i < r[i]) swap(f[i], f[r[i]]);
}
cplx w, wn, f1, f2;
for(int mid = 1; mid < limit; mid <<= 1) {
wn = cos(pi / mid) + type * 1i * sin(pi / mid);
for(int i = 0; i < limit; i += mid << 1) {
w = 1.0;
for(int j = 0; j < mid; ++j, w *= wn) {
f1 = f[i + j], f2 = w * f[i + mid + j];
f[i + j] = f1 + f2;
f[i + mid + j] = f1 - f2;
}
}
}
}
void mul(int* F, int n, int *G, int m, int *H) {
static cplx f[1 << 22], g[1 << 22];
int l = __lg(n + m) + 1;
int limit = 1 << l;
fill(f, f + limit, 0);
fill(g, g + limit, 0);
for(int i = 0; i <= n; ++i) f[i].real(F[i]);
for(int i = 0; i <= m; ++i) g[i].real(G[i]);
FFT(f, limit, 1.0);
FFT(g, limit, 1.0);
for(int i = 0; i < limit; ++i) f[i] *= g[i];
FFT(f, limit, -1.0);
for(int i = 0; i <= n + m; ++i) H[i] = int(f[i].real() / limit + 0.5);
}
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for(int i = 0; i <= n; ++i) cin >> f[i];
for(int i = 0; i <= m; ++i) cin >> g[i];
poly::mul(f, n, g, m, h);
for(int i = 0; i <= n + m; ++i) cout << h[i] << " ";
return 0;
}
NTT:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace poly {
constexpr int mod = 998244353, G = 3, gi = 332748118, img = 86583718, inv2 = 499122177, inv2i = 954952494;
struct modint {
int x;
modint(ll v = 0): x((v % mod + mod) % mod) {}
friend modint ksm(modint x, ll y) {
modint ret = 1;
while(y) {if(y & 1) ret *= x; x *= x, y >>= 1;}
return ret;
}
friend modint operator + (const modint& x, const modint& y) {return x.x + y.x >= mod ? x.x + y.x - mod : x.x + y.x;}
friend modint operator - (const modint& x, const modint& y) {return x.x < y.x ? x.x - y.x + mod : x.x - y.x;}
friend modint operator * (const modint& x, const modint& y) {return (ll)x.x * y.x % mod;}
friend modint operator / (const modint& x, const modint& y) {return x * ksm(y, mod - 2);}
friend modint operator - (const modint& x) {return mod - x.x;}
modint operator = (const modint& _) {x = _.x; return *this;}
modint operator += (const modint& _) {*this = *this + _; return *this;}
modint operator -= (const modint& _) {*this = *this - _; return *this;}
modint operator *= (const modint& _) {*this = *this * _; return *this;}
modint operator /= (const modint& _) {*this = *this / _; return *this;}
bool operator == (const modint& _) const {return x == _.x;}
bool operator != (const modint& _) const {return x != _.x;}
friend istream& operator >> (istream& in, modint& _) {static ll tmp; in >> tmp; _.x = tmp % mod; return in;}
friend ostream& operator << (ostream& out, const modint& _) {return out << _.x;}
};
modint ksm(ll x, ll y) {return ksm(modint(x), y);}
int r[1 << 22];
modint power[2][23];
void init(int len) {
int l = __lg(len) + 1;
int limit = 1 << l;
for(int i = 1; i < limit; ++i) r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
power[0][l] = ksm(gi, (mod - 1) / limit);
power[1][l] = ksm(G, (mod - 1) / limit);
for(int i = l; i >= 1; --i) {
power[0][i - 1] = power[0][i] * power[0][i];
power[1][i - 1] = power[1][i] * power[1][i];
}
}
void NTT(modint* f, int n, bool type) {
for(int i = 1; i < n; ++i) {
if(i < r[i]) swap(f[i], f[r[i]]);
}
modint w, wn, h1, h2;
for(int mid = 1, lg = 0; mid < n; mid <<= 1, ++lg) {
wn = power[type][lg + 1];
for(int i = 0; i < n; i += mid << 1) {
w = 1;
for(int j = 0; j < mid; ++j, w *= wn) {
h1 = f[i + j], h2 = w * f[i + mid + j];
f[i + j] = h1 + h2, f[i + mid + j] = h1 - h2;
}
}
}
if(type) return;
modint inv = ksm(n, mod - 2);
for(int i = 0; i < n; ++i) f[i] *= inv;
}
void mul(modint* F, int n, modint *G, int m, modint *H) {
static modint f[1 << 22], g[1 << 22];
int l = __lg(n + m) + 1;
int limit = 1 << l;
copy(F, F + limit, f);
copy(G, G + limit, g);
init(n + m);
NTT(f, limit, true);
NTT(g, limit, true);
for(int i = 0; i < limit; ++i) H[i] = f[i] * g[i];
NTT(H, limit, false);
}
}
using poly::modint;
int n, m;
modint f[1 << 22], g[1 << 22], h[1 << 22];
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for(int i = 0; i <= n; ++i) cin >> f[i];
for(int i = 0; i <= m; ++i) cin >> g[i];
poly::mul(f, n, g, m, h);
for(int i = 0; i <= n + m; ++i) cout << h[i] << " ";
return 0;
}
力老师
先把 \(q_{j}\) 从 \(F_{j}\) 中消掉。
再把 \(F_{j}\) 分成两部分算,一个 \(\sum\limits_{i = 1}^{j - 1}\dfrac{q_{i}}{(i - j)^{2}}\) 一个 \(-\sum\limits_{i = j + 1}^{n}\dfrac{q_{i}}{(i - j)^{2}}\)。
令多项式 \(Q(x) = \sum\limits_{i = 1}^{n}q_{i}x^{i}\),也就是 \([x^{i}]Q(x) = q_{i}\),特别的,\([x^{0}]Q(x) = 0\)。
令多项式 \(G(x) = \sum\limits_{i = 1}^{n}\dfrac{x^{i}}{i^{2}}\),也就是 \([x^{i}]G(x) = \dfrac{1}{i^{2}}\),特别的,\([x^{0}]G(x) = 0\)。
然后把上面的式子替换成多项式的系数的运算,有:
\[\begin{aligned} \sum\limits_{i = 1}^{j - 1}\dfrac{q_{i}}{(i - j)^{2}} &= \sum\limits_{i = 1}^{j - 1}[x^{i}]Q(x) \times [x^{j - i}]G(x)\\ &= \sum\limits_{i = 0}^{j}[x^{i}]Q(x) \times [x^{j - i}]G(x)\\ \sum\limits_{i = j + 1}^{n}\dfrac{q_{i}}{(i - j)^{2}} &= \sum\limits_{i = j + 1}^{n}[x^{i}]Q(x) \times [x^{i - j}]G(x)\\ &= \sum\limits_{i = j}^{n}[x^{i}]Q(x) \times [x^{i - j}]G(x) \end{aligned} \]可以发现上面的部分就是一个卷积的形式,下面的部分是一个「差卷积」,把其中一个多项式的次数反转一下即可(即令 \([x^{i}]H(x) = [x^{n - i + 1}]G(x)\))。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
constexpr int lim = 1 << 18;
namespace poly {
typedef complex<double> cplx;
const double pi = acos(-1.0);
void FFT(cplx *f, int limit, double type) {
static int r[lim];
for(int i = 1, l = __lg(limit); i < limit; ++i) {
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (l - 1));
if(i < r[i]) swap(f[i], f[r[i]]);
}
cplx w, wn, f1, f2;
for(int mid = 1; mid < limit; mid <<= 1) {
wn = cos(pi / mid) + type * 1i * sin(pi / mid);
for(int i = 0; i < limit; i += mid << 1) {
w = 1.0;
for(int j = 0; j < mid; ++j, w *= wn) {
f1 = f[i + j], f2 = w * f[i + mid + j];
f[i + j] = f1 + f2;
f[i + mid + j] = f1 - f2;
}
}
}
}
void mul(double* F, int n, double *G, int m, double *H) {
static cplx f[lim], g[lim];
int l = __lg(n + m) + 1;
int limit = 1 << l;
fill(f, f + limit, 0);
fill(g, g + limit, 0);
for(int i = 0; i <= n; ++i) f[i].real(F[i]);
for(int i = 0; i <= m; ++i) g[i].real(G[i]);
FFT(f, limit, 1.0);
FFT(g, limit, 1.0);
for(int i = 0; i < limit; ++i) f[i] *= g[i];
FFT(f, limit, -1.0);
for(int i = 0; i <= n + m; ++i) H[i] = f[i].real() / limit;
}
}
int n;
double q[lim], i2[lim], res1[lim], res2[lim];
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n;
for(int i = 1; i <= n; ++i) {
cin >> q[i];
i2[i] = 1.0 / i / i;
}
poly::mul(q, n, i2, n, res1);
reverse(q + 1, q + 1 + n);
poly::mul(q, n, i2, n, res2);
for(int i = 1; i <= n; ++i) {
cout << fixed << setprecision(3) << res1[i] - res2[n - i + 1] << '\n';
}
return 0;
}
咕咕咕捏。
标签:const,int,题解,return,多项式,operator,modint,初三,mod From: https://www.cnblogs.com/A-box-of-yogurt/p/18083310