Solution
裸的多维FFT,用
BlueStein
算法。。把里面的复数域的变换,改成膜意义下的变换就好了。
因为这道题维数真的不高。。而且FNT复杂度比较大,所以直接暴力卷积了。。
所以就要打一个FWT一样的东西。
改了Hillan的模板~
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3101010;
const int G = 22;
const int MOD = 330301441;
const int INV2 = (MOD + 1) >> 1;
typedef long long ll;
inline char get(void) {
static char buf[100000], *S = buf, *T = buf;
if (S == T) {
T = (S = buf) + fread(buf, 1, 100000, stdin);
if (S == T) return EOF;
}
return *S++;
}
template<typename T>
inline void read(T &x) {
static char c; x = 0;
for (c = get(); c < '0' || c > '9'; c = get());
for (; c >= '0' && c <= '9'; c = get()) x = x * 10 + c - '0';
}
ll w1[2][MAXN];
int g, invg, n, m, M, num, gh, invgh, K, in;
ll X;
inline int Pow(int a, int b) {
ll c = 1;
while (b) {
if (b & 1) c = (ll)c * a % MOD;
b >>= 1; a = (ll)a * a % MOD;
}
return c;
}
inline int Inv(int x) {
return Pow(x, MOD - 2);
}
ll c[MAXN], b[2][MAXN];
int C, N;
ll ans;
int Nf;
inline void Prep(void) {
gh = Pow(G, (MOD - 1) / 2 / K);
invgh = Inv(gh); Nf = 2 * K;
w1[0][0] = w1[1][0] = 1;
for (int i = 1; i < K * 3; i++) {
w1[0][i] = w1[0][i - 1] * invgh % MOD;
w1[1][i] = w1[1][i - 1] * gh % MOD;
}
N = 1;
for (; (1 << N) < (3 * K); N++);
for (int i = 0; i < 2 * K; i++) {
b[0][i] = w1[0][i * i % Nf];
b[1][i] = w1[1][i * i % Nf];
}
}
inline void Add(int &x, int a) {
x += a; while (x >= MOD) x -= MOD;
}
inline void DFT(int* a, int d, int n, int r) {
for (int i = 0; i < n; i++)
c[n - i] = b[r ^ 1][i] * a[i * d] % MOD;
for (int i = n; i < 2 * n; i++) {
int pos = i - n;
pos *= d; a[pos] = 0;
for (int j = 0; j <= i; j++)
Add(a[pos], b[r][i - j] * c[j] % MOD);
}
for (int i = 0; i < n; i++)
a[i * d] = b[r ^ 1][i] * a[i * d] % MOD;
if (!r) {
int INV = Inv(n);
for (int i = 0; i < n; i++)
a[i * d] = (ll)a[i * d] * INV % MOD;
}
for (int i = 0; i < (1 << N); i++) c[i] = 0;
}
void FWT(int* a, int n, int m, int r) {
int len = 1;
for (int i = 0; i < m; len *= K, i++)
for (int j = 0; j < n; j += len * K)
for (int k = 0; k < len; k++)
DFT(a + j + k, len, K, r);
}
int Da[MAXN];
int s[MAXN], buc[MAXN], pro1, pro2;
int lim = 100000, mx;
int T, fac;
int main(void) {
read(T);
while (T--) {
read(in); read(K); read(X); mx = m = ans = 0; fac = 1;
for (int i = 0; i <= lim; i++) buc[i] = 0;
for (int i = 1; i <= in; i++) {
read(s[i]); buc[s[i]]++;
}
for (n = 1; n <= lim; n *= K) ++m;
for (int i = 0; i < n * 2; i++) Da[i] = 0;
pro1 = pro2 = 1;
for (int i = n; i >= 0; i--)
pro2 = (ll)pro2 * Pow(2, buc[i]) % MOD;
fac = Pow(INV2, in);
for (int i = 0; i <= n; i++) {
if (i) pro1 = (ll)pro1 * (Pow(2, buc[i - 1]) - 1) % MOD;
pro2 = (ll)pro2 * Pow(INV2, buc[i]) % MOD;
Da[i] = (ll)pro1 * pro2 % MOD;
}
ans = 0; Prep(); X %= MOD - 1;
FWT(Da, n, m, 1);
for (int i = 0; i < n; i++) Da[i] = Pow(Da[i], X);
FWT(Da, n, m, 0);
fac = Pow(fac, X);
for (int i = 0; i < n; i++) Da[i] = (ll)Da[i] * fac % MOD;
for (int i = 0; i < n; i++)
ans += (ll)Pow(i, i * 2) * Pow(Da[i], 3 * i) % MOD;
printf("%d\n", ans % MOD);
}
return 0;
}
本文介绍了一种利用BlueStein算法实现的多维快速傅立叶变换(FFT)方法,该方法适用于特定的多维数据处理场景。通过将复数域的变换调整为模意义下的变换,实现了高效的多维卷积计算。
526

被折叠的 条评论
为什么被折叠?



