求助 NTT 手写 Mod 不同函数传入值的常数影响
查看原帖
求助 NTT 手写 Mod 不同函数传入值的常数影响
500205
ssxvngn楼主2024/1/24 21:46

这是我的 NTT,用时 1.24s。

#include<bits/stdc++.h>
using i64 = long long;
const i64 mod = 998244353, G = 3;
inline i64 qpow(i64 a, i64 b) {
	i64 v = 1;
	while (b) b & 1 && ((v *= a) %= mod), (a *= a) %= mod, b >>= 1;
	return v;
}
const i64 invG = qpow(G, mod - 2);
const int maxn = 4e6 + 10;
inline i64 Mod(i64 x) {return x > mod ? x - mod : x;}
int rev[maxn];
i64 th[maxn];
inline void NTT(i64 *f, int n, bool isi) {
	for (int i = 0; i < n; i++) i < rev[i] && (std::swap(f[i], f[rev[i]]), 1);
	for (int l = 1, p = 2; p <= n; l <<= 1, p <<= 1) {
		i64 I = qpow(isi ? invG : G, (mod - 1) / p);
		th[0] = 1;
		for (int i = 1; i < l; i++) th[i] = th[i - 1] * I % mod;
		for (int s = 0; s < n; s += p) for (int t = 0; t < l; t++) {
			i64 v = th[t] * f[s + l + t] % mod;
			f[s + l + t] = Mod(f[s + t] - v + mod);
			f[s + t] = Mod(f[s + t] + v); 
		}
	}
}
i64 f[maxn], g[maxn];
int main() {
	int n, m; scanf("%d%d", &n, &m);
	for (int i = 0; i <= n; i++) scanf("%lld", &f[i]);
	for (int i = 0; i <= m; i++) scanf("%lld", &g[i]);
	for (m += n, n = 1; n <= m; n <<= 1);
	for (int i = 1; i < n; i++) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) ? (n >> 1) : 0);
	NTT(f, n, 0), NTT(g, n, 0);
	for (int i = 0; i < n; i++) (f[i] *= g[i]) %= mod;
	NTT(f, n, 1);
	i64 invn = qpow(n, mod - 2);
	for (int i = 0; i <= m; i++) printf("%lld ", f[i] * invn % mod);
	return 0;
}

如果把 22 23 行改为

			f[s + l + t] = Mod(f[s + t] - v);
			f[s + t] = Mod(f[s + t] + v); 

用时 1.99s。

如果改为:

			f[s + l + t] = Mod(f[s + t] - v);
			f[s + t] = Mod(f[s + t] + v - mod); 

用时 2.72s。

而这三部分的差距仅仅是 Mod 函数里第一种传入的都是正数,第二种一正一负,第三种都是负数。

每种都测了三四次,应该不是评测波动。

求问是为什么 QAQ。

2024/1/24 21:46
加载中...