多项式板子
持续整理中
(不会打啊所以就放了)
这里先放几个散乱的板子,写的非常乱
合并在一起的板子蜜汁RE了....大力Debug中
不全,有的没打过
多项式乘法
给定两个多项式\(A(x)\),\(B(x)\),求\(C(x)=A(x)*B(x)\)。在\(\mod 998244353\)进行。
FFT模板:
#include <bits/stdc++.h>
using namespace std;
struct Complex
{
double r, v;
Complex(double rr = 0, double vv = 0) : r(rr), v(vv){}
Complex &operator=(double x){r = x; v = 0;return *this;}
friend Complex operator+(const Complex &a, const Complex &b){return Complex(a.r + b.r, a.v + b.v);}
friend Complex operator-(const Complex &a, const Complex &b){return Complex(a.r - b.r, a.v - b.v);}
friend Complex operator*(const Complex &a, const Complex &b){return Complex(a.r * b.r - a.v * b.v, a.r * b.v + b.r * a.v);}
};
int r[4000010];
Complex a[4000010], b[4000010], ans[4000010];
int N, M;
void FFT(Complex *A, int n, int flag)
{
Complex w, w1, t, *A0, *A1;
for (int i = 0; i < n; i++)
if(i < r[i])
swap(A[i], A[r[i]]);
for (int i = 1; i < n; i <<= 1)
{
w1 = Complex(cos(acos(-1) / i), sin(acos(-1) * flag / i));
for (int j = 0; j < n; j += i << 1)
{
w = 1;
A0 = A + j;
A1 = A0 + i;
for (int k = 0; k < i; k++, A0++, A1++, w = w * w1)
{
t = (*A1) * w;
(*A1) = (*A0) - t;
(*A0) = (*A0) + t;
}
}
}
}
int main()
{
scanf("%d%d", &N, &M);
for (int i = 0; i <= N; i++)
scanf("%lf", &a[i].r);
for (int i = 0; i <= M; i++)
scanf("%lf", &b[i].r);
int tot = 1, len = 0;
while (tot <= N + M)
tot <<= 1, len++;
for (int i = 0; i < tot; i++)
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (len - 1));
FFT(a, tot, 1);
FFT(b, tot, 1);
for (int i = 0; i < tot; i++)
ans[i] = a[i] * b[i];
FFT(ans, tot, -1);
for (int i = 0; i <= N + M; i++)
printf("%d%c", (int)(ans[i].r / tot + 0.2) , i == N + M ? '\n' : ' ');
return 0;
}
FNTT模板:
//rqj 模板
#include <bits/stdc++.h>
using namespace std;
#define p 998244353
#define MAXN 4323432
int n, m;
int r[MAXN], a[MAXN], b[MAXN], ans[MAXN];
int qpow(int x, int y)
{
int ans = 1;
while (y > 0)
{
if (y & 1)
ans = (1LL * ans * x) % p;
x = (1LL * x * x) % p;
y >>= 1;
}
return ans;
}
void FNTT(int *A, int len, int flag)
{
int gn, g, t, *A0, *A1;
for (int i = 0; i < len; i++)
if (i < r[i])
swap(A[i], A[r[i]]);
for (int i = 1; i < len; i <<= 1)
{
gn = qpow(3, (p - 1) / (i * 2));
for (int j = 0; j < len; j += (i << 1))
{
g = 1;
A0 = A + j;
A1 = A0 + i;
for (int k = 0; k < i; k++, A0++, A1++, g = (1LL * g * gn) % p)
{
t = (1LL * (*A1) * g) % p;
(*A1) = (((*A0) - t) % p + p) % p;
(*A0) = ((*A0) + t) % p;
}
}
}
if (flag == -1)
{
reverse(A + 1, A + len);
int inv = qpow(len, p - 2);
for (int i = 0; i < len; i++)
A[i] = (1LL * A[i] * inv) % p;
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 0; i <= m; i++)
scanf("%d", &b[i]);
int len = 1, bin = 0;
for (; len <= n + m; len <<= 1, bin++);
for (int i = 0; i < len; i++)
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (bin - 1));
FNTT(a, len, 1);
FNTT(b, len, 1);
for (int i = 0; i < len; i++)
ans[i] = (1LL * a[i] * b[i]) % p;
FNTT(ans, len, -1);
for (int i = 0; i <= n + m; i++)
printf("%d%c", ans[i], i == n + m ? '\n' : ' ');
return 0;
}
多项式乘法(任意模数)
给定两个多项式\(A(x)\),\(B(x)\),求\(C(x)=A(x)*B(x)\)。在\(\mod p\)下进行。
把\(a_i\)拆成\(a_{i1}*32768+a_{i2}\)的形式
然后都拆开做FFT
本题精度要求高,omega不能由单位根乘出来,必须要每次使用每次获取。
#include <bits/stdc++.h>
using namespace std;
const double pi = acos(-1);
struct Complex
{
long double r, v;
Complex(long double rr = 0, long double vv = 0) : r(rr), v(vv){}
Complex &operator=(long double x){r = x; v = 0;return *this;}
friend Complex operator+(const Complex &a, const Complex &b){return Complex(a.r + b.r, a.v + b.v);}
friend Complex operator-(const Complex &a, const Complex &b){return Complex(a.r - b.r, a.v - b.v);}
friend Complex operator*(const Complex &a, const Complex &b){return Complex(a.r * b.r - a.v * b.v, a.r * b.v + b.r * a.v);}
};
long long r[543211];
Complex a1[543211], a2[543211], b1[543211], b2[543211], ans1[543211], ans2[543211], ans3[543211], ans4[543211];long long ans[543211];
long long a[543211], b[543211];
long long N, M, p;
long long qpow(long long x, long long y)
{
long long ans = 1;
while (y > 0)
{
if (y & 1)
ans = (1LL * ans * x) % p;
x = (1LL * x * x) % p;
y >>= 1;
}
return ans;
}
Complex get_omega(long long x, long long y, long long flag)
{
return Complex(std::cos(pi * y / x), std::sin(pi * y / x) * flag);
}
void FFT(Complex *A, long long n, long long flag)
{
Complex w, w1, t, *A0, *A1;
for (long long i = 0; i < n; i++)
if(i < r[i])
swap(A[i], A[r[i]]);
for (long long i = 1; i < n; i <<= 1)
{
for (long long j = 0; j < n; j += i << 1)
{
A0 = A + j;
A1 = A0 + i;
for (long long k = 0; k < i; k++, A0++, A1++)
{
w = get_omega(i, k, flag);
t = (*A1) * w;
(*A1) = (*A0) - t;
(*A0) = (*A0) + t;
}
}
}
}
signed main()
{
scanf("%lld%lld%lld", &N, &M, &p);
long long O2 = 32768;
for (long long i = 0; i <= N; i++)
{
scanf("%lld", &a[i]);
a[i] %= p;
a1[i].r = a[i] / O2;
a2[i].r = a[i] % O2;
}
for (long long i = 0; i <= M; i++)
{
scanf("%lld", &b[i]);
b[i] %= p;
b1[i].r = b[i] / O2;
b2[i].r = b[i] % O2;
}
long long tot = 1, len = 0;
while (tot <= max(N, M) * 2)
tot <<= 1, len++;
for (long long i = 0; i < tot; i++)
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (len - 1));
FFT(a1, tot, 1);
FFT(b1, tot, 1);
FFT(a2, tot, 1);
FFT(b2, tot, 1);
for (long long i = 0; i < tot; i++)
{
ans1[i] = a1[i] * b1[i];
ans2[i] = a2[i] * b1[i];
ans3[i] = a1[i] * b2[i];
ans4[i] = a2[i] * b2[i];
}
FFT(ans1, tot, -1);
FFT(ans2, tot, -1);
FFT(ans3, tot, -1);
FFT(ans4, tot, -1);
// for (long long i = 0; i < tot; i++)
// printf("%Lf %Lf %Lf %Lf\n", ans1[i].r, ans2[i].r, ans3[i].r, ans4[i].r);
for (long long i = 0; i < tot; i++)
{
ans[i] = ( ( ((((long long)round(ans1[i].r / tot)) % p) + p) % p * O2 %p * O2 % p +
((((long long)round(ans2[i].r / tot)) % p) + p) % p * O2 % p) % p +
( ((((long long)round(ans3[i].r / tot)) % p) + p) % p * O2 % p +
((((long long)round(ans4[i].r / tot)) % p) + p) % p ) % p ) % p;
}
for (long long i = 0; i <= N + M; i++)
printf("%lld%c", ans[i], i == N + M ? '\n' : ' ');
return 0;
}
多项式求逆
给定一个多项式\(F(x)\),求出一个多项式\(G(x)\),满足\(F(x)*G(x)\equiv1\pmod {x^n}\),对998244353取模。
#include <bits/stdc++.h>
using namespace std;
#define p 998244353
#define MAXN 2000010
int n;
int r[MAXN], A[MAXN], B[MAXN], C[MAXN];
int qpow(int x, int y)
{
int ans = 1;
while (y > 0)
{
if (y & 1)
ans = (1LL * ans * x) % p;
x = (1LL * x * x) % p;
y >>= 1;
}
return ans;
}
void FNTT(int *A, int n, int flag)
{
int gn, g, t, *A0, *A1;
for (int i = 0; i < n; i++)
if (i < r[i])
swap(A[i], A[r[i]]);
for (int i = 1; i < n; i <<= 1)
{
gn = qpow(3, (p - 1) / (i * 2));
for (int j = 0; j < n; j += (i << 1))
{
g = 1;
A0 = A + j;
A1 = A0 + i;
for (int k = 0; k < i; k++, A0++, A1++, g = (1LL * g * gn) % p)
{
t = (1LL * (*A1) * g) % p;
(*A1) = (((*A0) - t) % p + p) % p;
(*A0) = ((*A0) + t) % p;
}
}
}
if (flag == -1)
{
reverse(A + 1, A + n);
int inv = qpow(n, p - 2);
for (int i = 0; i < n; i++)
A[i] = (1LL * A[i] * inv) % p;
}
}
void poly_inv(int n)
{
if (n == 1)
{
B[0] = qpow(A[0], p - 2);
return;
}
poly_inv((n + 1) >> 1);
int len;
for (len = 1; len <= (n << 1); len <<= 1);
for (int i = 0; i < len; i++)
r[i] = (r[i >> 1] >> 1) | ((i & 1) ? (len >> 1) : 0);
memset(C, 0, sizeof(C));
for (int i = 0; i < n; i++)
C[i] = A[i];
FNTT(C, len, 1);
FNTT(B, len, 1);
for (int i = 0; i < len; i++)
B[i] = 1LL * B[i] * (((2 - 1LL * C[i] * B[i] % p) % p + p) % p) % p;
FNTT(B, len, -1);
for (int i = n; i < len; i++)
B[i] = 0;
}
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &A[i]);
poly_inv(n);
for (int i = 0; i < n; i++)
printf("%d%c", B[i], i == n - 1 ? '\n' : ' ');
return 0;
}
洛谷分治FFT模板
#include <bits/stdc++.h>
using namespace std;
#define p 998244353
#define MAXN 2000010
int n;
int r[MAXN], A[MAXN], B[MAXN], C[MAXN];
int qpow(int x, int y)
{
int ans = 1;
while (y > 0)
{
if (y & 1)
ans = (1LL * ans * x) % p;
x = (1LL * x * x) % p;
y >>= 1;
}
return ans;
}
void FNTT(int *A, int n, int flag)
{
int gn, g, t, *A0, *A1;
for (int i = 0; i < n; i++)
if (i < r[i])
swap(A[i], A[r[i]]);
for (int i = 1; i < n; i <<= 1)
{
gn = qpow(3, (p - 1) / (i * 2));
for (int j = 0; j < n; j += (i << 1))
{
g = 1;
A0 = A + j;
A1 = A0 + i;
for (int k = 0; k < i; k++, A0++, A1++, g = (1LL * g * gn) % p)
{
t = (1LL * (*A1) * g) % p;
(*A1) = (((*A0) - t) % p + p) % p;
(*A0) = ((*A0) + t) % p;
}
}
}
if (flag == -1)
{
reverse(A + 1, A + n);
int inv = qpow(n, p - 2);
for (int i = 0; i < n; i++)
A[i] = (1LL * A[i] * inv) % p;
}
}
void poly_inv(int n)
{
if (n == 1)
{
B[0] = qpow(A[0], p - 2);
return;
}
poly_inv((n + 1) >> 1);
int len;
for (len = 1; len <= (n << 1); len <<= 1);
for (int i = 0; i < len; i++)
r[i] = (r[i >> 1] >> 1) | ((i & 1) ? (len >> 1) : 0);
memset(C, 0, sizeof(C));
for (int i = 0; i < n; i++)
C[i] = A[i];
FNTT(C, len, 1);
FNTT(B, len, 1);
for (int i = 0; i < len; i++)
B[i] = 1LL * B[i] * (((2 - 1LL * C[i] * B[i] % p) % p + p) % p) % p;
FNTT(B, len, -1);
for (int i = n; i < len; i++)
B[i] = 0;
}
int main()
{
scanf("%d", &n);
for (int i = 1; i < n; i++)
{
scanf("%d", &A[i]);
A[i] = (p - A[i]) % p;
}
(A[0] += 1) %= p;
poly_inv(n);
for (int i = 0; i < n; i++)
printf("%d%c", B[i], i == n - 1 ? '\n' : ' ');
return 0;
}
拉格朗日插值
给定\(n-1\)次多项式的\(n\)个任意(横坐标互不相同)的点的点值式,给定一个x求对应的y。
#include <bits/stdc++.h>
using namespace std;
#define p 998244353
struct Vector
{
long long x, y;
}a[2010];
long long N;
long long inv(long long x)
{
long long k = p - 2;
long long ans = 1;
while (k > 0)
{
if (k & 1)
ans = ans * x % p;
x = x * x % p;
k >>= 1;
}
return ans;
}
long long query(long long x)
{
long long ans = 0;
for (int i = 1; i <= N; i++)
{
long long tmp = a[i].y;
for (int j = 1; j <= N; j++)
if (i != j)
{
tmp = tmp * (x - a[j].x) % p * inv(a[i].x - a[j].x) % p;
tmp = (tmp + p) % p;
}
(ans += tmp) %= p;
}
return ans;
}
int main()
{
scanf("%lld", &N);
long long k;
scanf("%lld", &k);
for (int i = 1; i <= N; i++)
scanf("%lld%lld", &a[i].x, &a[i].y);
printf("%lld\n", query(k));
return 0;
}
快速沃尔什变换
给定一个长度为\(2^n\)的序列A和B
求序列C满足\(\displaystyle C_i=\sum_{j@k=i}A_j*B_k\)当@=or,and,xor时C的值,在\(\mod998244353\)下进行
#include <bits/stdc++.h>
#define p 998244353
using namespace std;
long long a[150000], b[150000], ans[150000];
int n, len;
void FWT_or(long long *a)
{
for (int i = 1; (i << 1) <= len; i <<= 1)
for (int j = 0; j < len; j += i << 1)
for (int k = 0; k < i; k++)
(a[j + k + i] += a[j + k]) %= p;
}
void IFWT_or(long long *a)
{
for (int i = 1; (i << 1) <= len; i <<= 1)
for (int j = 0; j < len; j += i << 1)
for (int k = 0; k < i; k++)
(((a[j + k + i] -= a[j + k]) %= p) += p) %= p;
}
void FWT_and(long long *a)
{
for (int i = 1; (i << 1) <= len; i <<= 1)
for (int j = 0; j < len; j += i << 1)
for (int k = 0; k < i; k++)
(a[j + k] += a[j + k + i]) %= p;
}
void IFWT_and(long long *a)
{
for (int i = 1; (i << 1) <= len; i <<= 1)
for (int j = 0; j < len; j += i << 1)
for (int k = 0; k < i; k++)
(((a[j + k] -= a[j + k + i]) %= p) += p) %= p;
}
void FWT_xor(long long *a)
{
for (int i = 1; (i << 1) <= len; i <<= 1)
for (int j = 0; j < len; j += i << 1)
for (int k = 0; k < i; k++)
{
long long t = a[j + k];
(a[j + k] += a[j + k + i]) %= p;
a[j + k + i] = ((t - a[j + k + i]) % p + p) % p;
}
}
long long div2(long long x)
{
return x & 1 ? (x + p) / 2 : x / 2;
}
void IFWT_xor(long long *a)
{
for (int i = 1; (i << 1) <= len; i <<= 1)
for (int j = 0; j < len; j += i << 1)
for (int k = 0; k < i; k++)
{
long long t = a[j + k];
a[j + k] = div2(a[j + k] + a[j + k + i]) % p;
a[j + k + i] = div2(t - a[j + k + i] + p) % p;
}
}
int main()
{
scanf("%d", &n);
len = 1 << n;
for (int i = 0; i < len; i++)
scanf("%lld", &a[i]);
for (int i = 0; i < len; i++)
scanf("%lld", &b[i]);
FWT_or(a);
FWT_or(b);
for (int i = 0; i < len; i++)
ans[i] = a[i] * b[i] % p;
IFWT_or(a);
IFWT_or(b);
IFWT_or(ans);
for (int i = 0; i < len; i++)
printf("%lld%c", ans[i], i == len - 1 ? '\n' : ' ');
FWT_and(a);
FWT_and(b);
for (int i = 0; i < len; i++)
ans[i] = a[i] * b[i] % p;
IFWT_and(a);
IFWT_and(b);
IFWT_and(ans);
for (int i = 0; i < len; i++)
printf("%lld%c", ans[i], i == len - 1 ? '\n' : ' ');
FWT_xor(a);
FWT_xor(b);
for (int i = 0; i < len; i++)
ans[i] = a[i] * b[i] % p;
IFWT_xor(a);
IFWT_xor(b);
IFWT_xor(ans);
for (int i = 0; i < len; i++)
printf("%lld%c", ans[i], i == len - 1 ? '\n' : ' ');
return 0;
}