[FWT][BlueStein Algorithm]CodeChef XORTREEH

本文介绍了一种利用BlueStein算法实现的多维快速傅立叶变换(FFT)方法,该方法适用于特定的多维数据处理场景。通过将复数域的变换调整为模意义下的变换,实现了高效的多维卷积计算。

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;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值