xuyiyang @ 2023-11-25 13:34:36
开 long double,注意 FFT 单位根预处理不能用乘法,如:
w[0].a = 1;
cp t(cos(2 * pi / k), sin(2 * pi / k));
for (int i = 1; i < k; i ++ ) w[i] = w[i - 1] * t;
要这样:
for (int i = 0; i < k; i ++ ) w[i] = cp(cos(i * 2 * pi / k), sin(i * 2 * pi / k));
还有一些取模问题。以下是我的 MTT ,供参考。
void MTT(int P)
{
int bit = log_2(n + m); k = 1 << bit + 1;
for (int i = 0; i < k; i ++ ) r[i] = r[i >> 1] >> 1 | (i & 1) << bit;
for (int i = 0; i < k; i ++ ) w[i] = cp(cos(i * 2 * pi / k), sin(i * 2 * pi / k));
for (int i = 0; i < k; i ++ ) a[i] = cp((LD)(p[i] / L), (LD)(p[i] % L)), b[i] = cp((LD)(p[i] / L), (LD)(-p[i] % L));
for (int i = 0; i < k; i ++ ) c[i] = cp((LD)(q[i] / L), (LD)(q[i] % L));
FFT(a, 1); FFT(b, 1); FFT(c, 1); // FFT 正常写即可。
for (int i = 0; i < k; i ++ ) c[i].a /= k, c[i].b /= k;
for (int i = 0; i < k; i ++ ) a[i] = a[i] * c[i];
for (int i = 0; i < k; i ++ ) b[i] = b[i] * c[i];
FFT(a, 0); FFT(b, 0);
for (int i = 0; i <= n + m; i ++ )
{
LL a1b1 = (LL)floor((a[i].a + b[i].a) / 2 + 0.5) % P;
LL a1b2 = (LL)floor((a[i].b + b[i].b) / 2 + 0.5) % P;
LL a2b1 = (LL)(floor(a[i].b + 0.5) - a1b2) % P;
LL a2b2 = (LL)(floor(b[i].a + 0.5) - a1b1) % P;
res[i] = ((a1b1 * L % P * L % P + (a1b2 + a2b1) % P * L % P) % P + a2b2) % P;
res[i] = (res[i] % P + P) % P;
}
}