FWT背板笔记

板子

背板子.jpg

\(Fwt\)用于解决这样的问题

\[C_i=\sum_{j\bigoplus k=i}A_j\times B_k\]

其中\(\bigoplus\)是一种二元运算符,如\(or,and,xor\)

首先我们直接做复杂度显然高达\(4^n\),或许可以利用一些枚举子集的技术做到\(3^n\),但是还是非常难以接受

于是我们考虑能否像\(fft\)那样构造出一种变换\(tf\),使得\(tf(C)=tf(A)*tf(B)\)(这里是逐位相乘),同时快速完成这个变换以及逆变换呢

下面以\(or\)卷积为例

我们设\(tf(A)(i)=\sum_{j|i=i}A_j\)

发现这个\(j|i=i\)就是说\(j\)\(i\)的子集啊

于是

\[tf(A)(i)*tf(B)(i)=\sum_{j|i=i}A_j\times \sum_{k|i=i}B_k\]

既然\(j,k\)都是\(i\)的子集,那么\(j|k\)显然也是\(i\)的子集,设\(t=j|k\)

于是

\[tf(A)(i)*tf(B)(i)=\sum_{(k|j)|i=i}A_j\times B_k=\sum_{t|i=i}C_t=tf(C)(i)\]

我们发现如果这样构造\(tf\),我们是可以得到\(tf(A)*tf(B)=tf(C)\)这样的性质的,于是就可以像\(fft\)那样直接逐位相乘之后逆变换了

考虑如何进行变换

变换如下

\[tf(A)=\begin{cases}(tf(A_0),tf(A_0+A_1)) & n\gt0 \\ A & n=0\end{cases}\]

\(A_0\)\(A\)的前\(2^{n-1}\)项组成的多项式,\(A_1\)是后\(2^{n-1}\)项组成的多项式

\(n=0\)的时候,\(tf(A)=A\)成立这非常显然啊

考虑一下\(n>0\)的情况

那个\((tf(A_0),tf(A_0+A_1))\)就是把两个\(2^{n-1}\)的多项式连接起来的意思

我们对于\(tf(A)\)的前\(2^{n-1}\)项,就是\(A_0\)的变换,跟\(A_1\)没有什么关系,因为这前\(2^{n-1}\)项第\(n\)位都是\(0\),不可能跟后\(2^{n-1}\)项第\(n\)位都是\(1\)产生关系

考虑后\(2^{n-1}\)项,根据一个非常感性的理解,后\(2^{n-1}\)项的第\(n\)位都是\(1\),我们构造出多项式\(A_0+A_1\),只看后面的\(n-1\)位自然是满足我们的\(tf\)的规则的,就是\(j\)\(i\)的子集,又由于\(i\)的第一位是\(1\),所以\(j\)的第一位是\(0\)\(1\)都可以,所以我们直接用\(A_0+A_1\)就好了

类似的,我们也可以推出逆变换

\[itf(A)=\begin{cases}(itf(A_0),itf(A_0-A_1)) & n\gt0 \\ A & n=0\end{cases}\]

于是我们就可以写出\(or\)卷积的代码

inline void Fwtor(LL *f,int o) {
    for(re int i=2;i<=len;i<<=1)
        for(re int ln=i>>1,l=0;l<len;l+=i)
            for(re int x=l;x<l+ln;++x)
                f[ln+x]+=o*f[x];
}

\(and\)卷积和\(or\)卷积类似

我们设变换\(tf(A)(i)=\sum_{j\&i=i}A_j\)

发现\(j\&i=i\)就是说\(j\)\(i\)的超集

我们也能相应写出变换

\[tf(A)=\begin{cases}(tf(A_0+A_1),tf(A_1)) & n\gt0 \\ A & n=0\end{cases}\]

以及逆变换

\[itf(A)=\begin{cases}(itf(A_0-A_1),itf(A_1)) & n\gt0 \\ A & n=0\end{cases}\]

以及代码

inline void Fwtand(LL *f,int o) {
    for(re int i=2;i<=len;i<<=1)
        for(re int ln=i>>1,l=0;l<len;l+=i)
            for(re int x=l;x<l+ln;++x)
                f[x]+=o*f[ln+x];
}

\(xor\)卷积就有些不一样了呀

首先我不是很知道这个变换的实际含义是什么

据fuge说是曼哈顿距离转切比雪夫距离

我们直接摆结论

\[tf(A)=\begin{cases}(tf(A_0+A_1),tf(A_0-A_1)) & n\gt0 \\ A & n=0\end{cases}\]

尝试证明一下?对不起我咕了,挂一个yyb跑路了

板子还是放上来吧

inline void Fwtxor(LL *f,int o) {
    LL Inv;
    if(o==1) Inv=1;else Inv=ksm(2,mod-2);
    for(re int i=2;i<=len;i<<=1)
        for(re int ln=i>>1,l=0;l<len;l+=i)
            for(re int x=l;x<l+ln;++x) {
                LL g=f[x],h=f[ln+x];
                f[x]=(g+h)%mod,f[ln+x]=(g-h+mod)%mod;
                f[x]=(f[x]*Inv)%mod;f[ln+x]=(f[ln+x]*Inv)%mod;
            }
}

最后挂一个完整的板子吧

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define re register
#define LL long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
const int maxn=(1<<17)+6;
inline int read() {
    char c=getchar();int x=0;while(c<'0'||x>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int mod=998244353;
int n,len;
LL A[maxn],B[maxn],a[maxn],b[maxn];
inline void Fwtor(LL *f,int o) {
    for(re int i=2;i<=len;i<<=1) 
        for(re int ln=i>>1,l=0;l<len;l+=i)  
            for(re int x=l;x<l+ln;++x)
                f[x+ln]+=f[x]*o,f[x+ln]=(f[x+ln]+mod)%mod;
}
inline void Fwtand(LL *f,int o) {
    for(re int i=2;i<=len;i<<=1) 
        for(re int ln=i>>1,l=0;l<len;l+=i)
            for(re int x=l;x<l+ln;++x)
                f[x]+=f[x+ln]*o,f[x]=(f[x]+mod)%mod;
}
inline void Fwtxor(LL *f,int o) {
    int Inv;
    if(o==1) Inv=1;else Inv=499122177;
    for(re int i=2;i<=len;i<<=1) 
        for(re int ln=i>>1,l=0;l<len;l+=i) 
            for(re int x=l;x<l+ln;++x) {
                int g=f[x],h=f[x+ln];
                f[x]=(g+h)%mod;f[ln+x]=(g-h+mod)%mod;
                f[x]=1ll*f[x]*Inv%mod;f[x+ln]=1ll*f[x+ln]*Inv%mod;
            }
}
int main() {
    n=read();len=(1<<n);
    for(re int i=0;i<len;i++) a[i]=A[i]=read();
    for(re int i=0;i<len;i++) b[i]=B[i]=read();
    Fwtor(A,1),Fwtor(B,1);
    for(re int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod;
    Fwtor(A,-1);
    for(re int i=0;i<len;i++) printf("%lld ",A[i]);puts("");
    for(re int i=0;i<len;i++) A[i]=a[i];
    for(re int i=0;i<len;i++) B[i]=b[i];
    Fwtand(A,1),Fwtand(B,1);
    for(re int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod;
    Fwtand(A,-1);
    for(re int i=0;i<len;i++) printf("%lld ",A[i]);puts("");
    for(re int i=0;i<len;i++) A[i]=a[i];
    for(re int i=0;i<len;i++) B[i]=b[i];
    Fwtxor(A,1),Fwtxor(B,1);
    for(re int i=0;i<len;i++) A[i]=1ll*A[i]*B[i]%mod;
    Fwtxor(A,-1);
    for(re int i=0;i<len;i++) printf("%lld ",A[i]);puts("");
    return 0;
}

转载于:https://www.cnblogs.com/asuldb/p/10686125.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值