FWT总结

本文介绍了FWT(傅立叶变换)在解决位运算相关问题中的应用,如Bob and Alice玩数字游戏、图的最小染色数问题和二进制表格操作。通过FWT可以将复杂度降低,实现n^2/2^n到n^2的算法优化。文章详细解释了如何使用FWT处理位运算卷积,并通过具体题目实例展示FWT的应用,包括Jzzhu and Numbers问题的解决方案,涉及高维前缀和与反演的概念。
摘要由CSDN通过智能技术生成

花了一段时间把FWT技能给点了,姑且在这里记录下我对FWT的理解,其中大部分内容参考这个博客

首先,要知道FWT是用来处理这类问题的:

Ck=ij=kAiBj

其中异或可以换成其他位运算(&,|)
也可以叫它位运算卷积

对于其详细介绍以及如何在 nlogn 下完成可以看看这个博客,大概的过程就是把利用FWT把 A,B 转换成 A,B ,然后有关系式

Ck=AkBk
,然后再把 C 进行反变换ifwt变成 C

然后贴一份模板

typedef long long ll;
const int mod = 1e9+7;

ll mypow(ll x, ll n) {
    ll ret = 1;
    for (; n; n >>= 1) {
        if (n & 1) ret = ret * x % mod;
        x = x * x % mod;
    }
    return ret;
}

const ll inv2 = mypow(2, mod - 2);

void fwtXor(ll* a, int len) {
    if (len == 1) return;
    int h = len >> 1;
    fwtXor(a, h);
    fwtXor(a + h, h);
    for (int i = 0; i < h; ++i) {
        ll x1 = a[i];
        ll x2 = a[i + h];
        a[i] = (x1 + x2) % mod;
        a[i + h] = (x1 - x2 + mod) % mod;
    }
}

void ifwtXor(ll* a, int len) {
    if (len == 1) return;
    int h = len >> 1;
    for (int i = 0; i < h; ++i) {
        // y1=x1+x2
        // y2=x1-x2
        ll y1 = a[i];
        ll y2 = a[i + h];
        a[i] = (y1 + y2) * inv2 % mod;
        a[i + h] = (y1 - y2 + mod) * inv2 % mod;
    }
    ifwtXor(a, h);
    ifwtXor(a + h, h);
}

void fwtAnd(ll* a, int len) {
    if (len == 1) return;
    int h = len >> 1;
    fwtAnd(a, h);
    fwtAnd(a + h, h);
    for (int i = 0; i < h; ++i) {
        ll x1 = a[i];
        ll x2 = a[i + h];
        a[i] = (x1 + x2) % mod;
        a[i + h] = x2;
    }
}

void ifwtAnd(ll* a, int len) {
    if (len == 1) return;
    int h = len >> 1;
    for (int i = 0; i < h; ++i) {
        // y1=x1+x2
        // y2=x2
        ll y1 = a[i];
        ll y2 = a[i + h];
        a[i] = (y1 - y2 + mod) % mod;
        a[i + h] = y2;
    }
    ifwtAnd(a, h);
    ifwtAnd(a + h, h);
}

void fwtOr(ll* a, int len) {
    if (len == 1) return;
    int h = len >> 1;
    fwtOr(a, h);
    fwtOr(a + h, h);
    for (int i = 0; i < h; ++i) {
        ll x1 = a[i];
        ll x2 = a[i + h];
        a[i] = x1;
        a[i + h] = (x2 + x1) % mod;
    }
}

void ifwtOr(ll* a, int len) {
    if (len == 1) return;
    int h = len >> 1;
    for (int i = 0; i < h; ++i) {
        // y1=x1
        // y2=x2+x1
        ll y1 = a[i];
        ll y2 = a[i + h];
        a[i] = y1;
        a[i + h] = (y2 - y1 + mod) % mod;
    }
    ifwtOr(a, h);
    ifwtOr(a + h, h);
}

//len为2的幂
int len = 1 << 10;
void FWT(ll *a, ll *b, ll *c, int len) {
    fwtXor(a, len);
    fwtXor(b, len);
    for (int i = 0; i < len; ++i) {
        c[i] = a[i] * b[i] % mod;
    }
    ifwtXor(c, len);
}

道理我都懂,但是如何做题呢?
总之先做两题再说吧

  • Bob and Alice are playing numbers
    题意:给你一个数组 A ,和一个二元位运算符 op ,让你选择其中两个数 i j ,使得 i op j 最大
    题解:纯粹的模板题,用来验算模板正确性

    • color II
      题意:求图的最小染色数,按题目要求输出答案
      题解:图的最小染色数是经典的NP问题,显然可以看到这样一个规律:同一种颜色的点一定构成一个独立集。对于一个集合 s

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值