位运算卷积学习笔记
位运算卷积学习笔记
位运算卷积,即快速沃尔什变换
位运算卷积
首先要知道位运算卷积指的是
形式的式子,其中
快速莫比乌斯变换
卷积
先考虑暴力求解的时间复杂度是
定义
由此我们得到了一个构造,而且不难发现这其实就是
代码
int n;
int A[1<<n],B[1<<n],C[1<<n];
void FMT_OR(int n,int *a,int type){
for(int i=0;i<n;i++){
for(int j=0;j<(1<<n);j++){
if(j&(1<<i))a[j]+=type*a[j^(1<<i)];
}
}
return ;
}
int main(){
cin>>n;
for(int i=0;i<(1<<n);i++)cin>>A[i];
for(int i=0;i<(1<<n);i++)cin>>B[i];
FMT_OR(n,A,1);
FMT_OR(n,B,1);
for(int i=0;i<(1<<n);i++)C[i]=A[i]*B[i];
FMT_OR(n,C,-1);
for(int i=0;i<(1<<n);i++)cout<<C[i]<<" ";
return 0;
}
卷积
和
于是考虑如何求解
代码
int n;
int A[1<<n],B[1<<n],C[1<<n];
void FMT_AND(int n,int *a,int type){
for(int i=0;i<n;i++){
for(int j=0;j<(1<<n);j++){
if(j&(1<<i))a[j^(1<<i)]+=type*a[j];
}
}
return ;
}
int main(){
cin>>n;
for(int i=0;i<(1<<n);i++)cin>>A[i];
for(int i=0;i<(1<<n);i++)cin>>B[i];
FMT_AND(n,A,1);
FMT_AND(n,B,1);
for(int i=0;i<(1<<n);i++)C[i]=A[i]*B[i];
FMT_AND(n,C,-1);
for(int i=0;i<(1<<n);i++)cout<<C[i]<<" ";
return 0;
}
快速沃尔什变换
变换
其实有关于
这个正确性是显然的,因为对于
关于逆变换则恰相反,只需要将前半段对后半段的贡献消去即可,也就是在后半段减去前半段。也就是
代码
int n;
int A[1<<n],B[1<<n],C[1<<n];
void FWT_OR(int n,int *a,int type){
for(int len=1;len<n;len<<=1){
for(int l=0;l<n;l+=(len<<1)){
for(int k=0;k<len;k++)a[l+len+k]+=type*a[l+k];
}
}
return ;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n;
for(int i=0;i<(1<<n);i++)cin>>A[i];
for(int i=0;i<(1<<n);i++)cin>>B[i];
FWT_OR(1<<n,A,1);
FWT_OR(1<<n,B,1);
for(int i=0;i<(1<<n);i++)C[i]=A[i]*B[i];
FWT_OR(1<<n,C,-1);
for(int i=0;i<(1<<n);i++)cout<<C[i]<<" ";
return 0;
}
卷积
依旧同理有
同理,当第
代码
int n;
int A[1<<n],B[1<<n],C[1<<n];
void FWT_AND(int n,int *a,int type){
for(int len=1;len<n;len<<=1){
for(int l=0;l<n;l+=(len<<1)){
for(int k=0;k<len;k++)a[l+k]+=type*a[l+len+k];
}
}
return ;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n;
for(int i=0;i<(1<<n);i++)cin>>A[i];
for(int i=0;i<(1<<n);i++)cin>>B[i];
FWT_AND(1<<n,A,1);
FWT_AND(1<<n,B,1);
for(int i=0;i<(1<<n);i++)C[i]=A[i]*B[i];
FWT_AND(1<<n,C,-1);
for(int i=0;i<(1<<n);i++)cout<<C[i]<<" ";
return 0;
}
卷积
引入一个新的运算符
更感性的理解,
不难看出,不管
由此,设
由此,该构造的正确性得证,接着考虑如何分治求解。当前位
而在逆变换时有
于是对于传参稍作改动,逆变换时
代码
int n;
int A[1<<n],B[1<<n],C[1<<n];
void FWT_XOR(int n,int *a,int type){
for(int len=1;len<n;len<<=1){
for(int l=0;l<n;l+=(len<<1)){
for(int k=0;k<len;k++){
ll A=a[l+k],B=a[l+len+k];
a[l+k]=(A+B)/type;
a[l+len+k]=(A-B)/type;
}
}
}
return ;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cin>>n;
for(int i=0;i<(1<<n);i++)cin>>A[i];
for(int i=0;i<(1<<n);i++)cin>>B[i];
FWT_XOR(1<<n,A,1);
FWT_XOR(1<<n,B,1);
for(int i=0;i<(1<<n);i++)C[i]=A[i]*B[i];
FWT_XOR(1<<n,C,2);
for(int i=0;i<(1<<n);i++)cout<<C[i]<<" ";
return 0;
}
拓展知识
矩阵角度的
假设
因为
所以应当有
拆分成
考虑到式子分出的
当
而当
不难考虑分治维护
进行,我们称这个矩阵为位矩阵。而如果需要进行逆变换,则需要上面位矩阵的逆矩阵。即可以通过
得到原序列。当然,逆矩阵不一定存在。当原矩阵存在一行或一列都是
卷积
不难构造出矩阵
满足
而下面的矩阵虽然也符合
考虑最上方的矩阵的逆
这和逆变换的
卷积
同理构造
满足
卷积
构造
满足
的性质
维
运算
重新审视
当
其逆矩阵为
运算
重新审视
当
其逆矩阵为
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律