【学习笔记】fwt&&fmt&&子集卷积
- 前言:yyb神仙的博客
FWT
基本思路:将多项式变成点值表达,点值相乘之后再逆变换回来得到特定形式的卷积;
多项式的次数界都为\(2^n\)的形式,\(A_0\)定义为前一半多项式(下标二进制第一位为\(0\)),\(A_1\)同理定义;
\((A,B)\)表示多项式\(A\)和\(B\)的直接拼接,FWT的结果都是一个点值表达,相乘表示点值相乘;
下面这些变换都满足线性,记\(n\)为二进制位数,复杂度:\(O(n\times 2^n)\);
or卷积
形式:
\[(A|B)_{k} = \sum_{i|j=k}A_i\times B_j
\]定义变换:
\[FWT(A) = (FWT(A_0),FWT(A_0+A_1))
\]则:\(FWT(A|B)=FWT(A) \times FWT(B)\)
归纳证明:
注意到\(A|B=(A_0|B_0,A_0|B_1+A_1|B_0+A_1|B_1)\) ;
\[\begin{align}
&FWT(A|B)\\
&=FWT(A_0|B_0,A_0|B_1+A_1|B_0+A_1|B_1)\\
&=(FWT(A_0|B_0),FWT(A_0|B_0+A_0|B_1+A_1|B_0+A_1|B_1))\\
&=(FWT(A_0)\times FWT(B_0),FWT(A_0)\times FWT(B_0)+FWT(A_0)
\\ &\times FWT(B_1)+FWT(A_1)\times FWT(B_0)+FWT(A_1)\times FWT(B_1))\\
&=(FWT(A_0),FWT(A_0+A_1))\times(FWT(B_0),FWT(B_0+B_1))\\
&=FWT(A)\times FWT(B)
\end{align}
\]逆变换:
\[IFWT(A) = (IFWT(A_0),IFWT(A_1-A_0))
\]代码:
void fwt(int*A,int F){
for(int i=1;i<n;i<<=1)
for(int j=0;j<n;j+=i<<1)
for(int k=0;k<i;++k){
if(~F)A[j+k+i]=(A[j+k+i]+A[j+k])%mod;
else A[j+k+i]=(A[j+k+i]-A[j+k]+mod)%mod;
}
}
and卷积
形式:
\[(A\&B)_{k} = \sum_{i\&j=k}A_i\times B_j
\]定义变换:
\[FWT(A) = (FWT(A_0+A_1),FWT(A_1))
\]则:\(FWT(A\&B)=FWT(A) \times FWT(B)\)
归纳证明:
注意到:\(A\&B=(A_0\&B_0+A_0\&B_1+A_1\&B_0,A_1\&B_1)\)
同理..
逆变换:
\[IFWT(A)=(IFWT(A_0-A_1),IFWT(A_1))
\]代码
void fwt(int*A,int F){
for(int i=1;i<n;i<<=1)
for(int j=0;j<n;j+=i<<1)
for(int k=0;k<i;++k){
if(~F)A[j+k]=(A[j+k]+A[j+k+i])%mod;
else A[j+k]=(A[j+k]-A[j+k+i]+mod)%mod;
}
}
xor卷积
形式
\[(A \oplus B)_{k} = \sum_{i \oplus j=k}A_i\times B_j
\]定义变换:
\[FWT(A) = (FWT(A_0+A_1),FWT(A_0-A_1))
\]则:\(FWT(A \oplus B)=FWT(A) \times FWT(B)\)
归纳证明:
注意到:\(A \oplus B=(A_0 \oplus B_0+A_1\oplus B_1 ,A_0\oplus B_1+A_1\oplus B_0)\)
同理..
逆变换:
\[IFWT(A)=(IFWT(A_0+A_1)/2,IFWT(A_0-A_1)/2)
\]代码:
void fwt(int*A,int F){
for(int i=1;i<n;i<<=1)
for(int j=0;j<n;j+=i<<1)
for(int k=0;k<i;++k){
int x=A[j+k],y=A[j+k+i];
A[j+k]=(x+y)%mod,A[j+k+i]=(x-y+mod)%mod;
if(!~F)A[j+k]=(ll)A[j+k]*iv2%mod,A[j+k+i]=(ll)A[j+k+i]*iv2%mod;
}
}
FMT
基本思路:将二进制的每一位看成一维,枚举每一维做前缀和就可以得到集合的前缀和;
直接上代码了......
子集前缀和(= or)
for(int i=0;i<n;++i)
for(int j=1<<i;j<1<<n;++j)
if(j>>i&1)f[j]+=f[j^(1<<i)];
超集前缀和(= and)
for(int i=0;i<n;++i)
for(int j=(1<<n)-1;j>=1<<i;--j)
if(j>>i&1)f[j^(1<<i)]+=f[j];
fmt的逆变换只需要将第二维反过来减即可;
优点是代码短,常数小,复杂度也是\(O(n \times 2^n)\)
子集卷积和
\(S,T\)是集合,求\(C:C_S = \sum_{S \subset T} A_T \times B_{S-T}\)
设\(A_{i,S}=[|S|=i]\times A_S\)
令\(C_i = \sum_{j\le i} A_{j}|B_{i-j}\)
这样就把问题变成了or卷积
由于我们只关心满足\(|T|=i\)的\(C_{i,T}\),所以是不会多算的;
时间复杂度:\(O(n^2 \times 2^n)\)
-
#include<bits/stdc++.h>
#define ll long long
#define mod 998244353
#define rg register
#define il inline
using namespace std;
const int N=22;
int n,m,p,f[N][1<<N],g[N][1<<N],d[N],fa[N],all,ny[3010];
int w[1<<N],cnt[1<<N],iw[1<<N],e[N];
il void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;}
il void dec(int&x,int y){x-=y;if(x<0)x+=mod;}
il void fwt(int*A,int F){
if(~F){
for(rg int i=0;i<n;++i)
for(rg int x=1<<i,j=x;j<all;++j)
if(j&x)inc(A[j],A[j^x]);
}else{
for(rg int i=0;i<n;++i)
for(rg int x=1<<i,j=all-1;~j;--j)
if(j&x)dec(A[j],A[j^x]);
}
}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
il bool check(int S){
for(rg int i=0;i<n;++i)fa[i]=i,d[i]=0;
for(int i=0;i<n;++i)if(S>>i&1)
for(int j=i+1;j<n;++j)if(S>>j&1){
if(!(e[i]>>j&1))continue;
d[i]++,d[j]++;
int fu=find(i),fv=find(j);
if(fu!=fv)fa[fu]=fv;
}
int lst=-1;
for(rg int i=0;i<n;++i)if(S>>i&1){
if(!~lst)lst=find(i);
if(lst!=find(i) || (d[i]&1))return true;
}
return false;
}
il int val(int x){
if(!p)return 1;
if(p&1)return x;
return (ll)x*x%mod;
}
int main(){
// freopen("walk.in","r",stdin);
// freopen("walk.out","w",stdout);
scanf("%d%d%d",&n,&m,&p);all=1<<n;
for(rg int i=0;i<m;++i){
int u,v;
scanf("%d%d",&u,&v),u--,v--;
e[u]|=1<<v;e[v]|=1<<u;
}
for(rg int i=0;i<n;++i)scanf("%d",&w[1<<i]);
ny[1]=1;for(rg int i=2;i<=2100;++i)ny[i]=(ll)(mod-mod/i)*ny[mod%i]%mod;
fwt(w,1);
for(rg int i=0;i<all;++i){
iw[i]=ny[w[i]];
iw[i]=val(iw[i]);
w[i]=val(w[i]);
cnt[i]=cnt[i>>1]+(i&1);
}
for(rg int i=0;i<all;++i)if(check(i))g[cnt[i]][i]=w[i];
for(rg int i=0;i<=n;++i)fwt(g[i],1);
f[0][0]=1;fwt(f[0],1);
for(rg int i=1;i<=n;++i){
int *F=f[i];//不加寻址优化是会T的
for(rg int j=1;j<=i;++j){
int *a=f[i-j],*b=g[j];
for(rg int k=0;k<all;++k){
inc(F[k],(ll)a[k]*b[k]%mod);
}
}
fwt(F,-1);
for(rg int j=0;j<all;++j)F[j]=cnt[j]==i?(ll)F[j]*iw[j]%mod:0;
if(i!=n)fwt(f[i],1);
}
cout<<f[n][all-1]<<endl;
return 0;
}
【学习笔记】fwt&&fmt&&子集卷积的更多相关文章
- CF914G Sum the Fibonacci FWT、子集卷积
传送门 一道良心的练习FWT和子集卷积的板子-- 具体来说就是先把所有满足\(s_a \& s_b = 0\)的\(s_a \mid s_b\)的值用子集卷积算出来,将所有\(s_a \opl ...
- UFLDL深度学习笔记 (六)卷积神经网络
UFLDL深度学习笔记 (六)卷积神经网络 1. 主要思路 "UFLDL 卷积神经网络"主要讲解了对大尺寸图像应用前面所讨论神经网络学习的方法,其中的变化有两条,第一,对大尺寸图像 ...
- [学习笔记]FWT——快速沃尔什变换
解决涉及子集配凑的卷积问题 一.介绍 1.基本用法 FWT快速沃尔什变换学习笔记 就是解决一类问题: $f[k]=\sum_{i\oplus j=k}a[i]*b[j]$ 基本思想和FFT类似. 首先 ...
- [学习笔记] $FWT$
\(FWT\)--快速沃尔什变化学习笔记 知识点 \(FWT\)就是求两个多项式的位运算卷积.类比\(FFT\),\(FFT\)大多数求的卷积形式为\(c_n=\sum\limits_{i+j=n}a ...
- 神经网络与深度学习笔记 Chapter 6之卷积神经网络
深度学习 Introducing convolutional networks:卷积神经网络介绍 卷积神经网络中有三个基本的概念:局部感受野(local receptive fields), 共享权重 ...
- DeepLearning.ai学习笔记(四)卷积神经网络 -- week4 特殊应用:人力脸识别和神经风格转换
一.什么是人脸识别 老实说这一节中的人脸识别技术的演示的确很牛bi,但是演技好尴尬,233333 啥是人脸识别就不用介绍了,下面笔记会介绍如何实现人脸识别. 二.One-shot(一次)学习 假设我们 ...
- 学习笔记TF028:实现简单卷积网络
载入MNIST数据集.创建默认Interactive Session. 初始化函数,权重制造随机噪声打破完全对称.截断正态分布噪声,标准差设0.1.ReLU,偏置加小正值(0.1),避免死亡节点(de ...
- DeepLearning.ai学习笔记(四)卷积神经网络 -- week1 卷积神经网络基础知识介绍
一.计算机视觉 如图示,之前课程中介绍的都是64* 64 3的图像,而一旦图像质量增加,例如变成1000 1000 * 3的时候那么此时的神经网络的计算量会巨大,显然这不现实.所以需要引入其他的方法来 ...
- DeepLearning.ai学习笔记(四)卷积神经网络 -- week2深度卷积神经网络 实例探究
一.为什么要进行实例探究? 通过他人的实例可以更好的理解如何构建卷积神经网络,本周课程主要会介绍如下网络 LeNet-5 AlexNet VGG ResNet (有152层) Inception 二. ...
随机推荐
- 《MySQL实战45讲》学习笔记1——MySQL的基础架构
在<极客时间>订阅了<MySQL实战45讲>专栏,总觉得看完和没看一样
- java基本数据类型的变量
一.整型变量 短整型(short).整型(int)和长整型(long),它们都可以定义整型变量,但是由于分配的内存空间不同,所能表示的数据的长度也不同. 我们可以定义并初始化一个整型变量: int a ...
- 使用php函数防止SQL注入方法
什么是SQL注入? SQL注入是指在你系统防御之外,某人将一段Mysql语句注入到你的数据库.注入通常发生在系统要求用户输入数据的时候,比如用户名的输入,用户可能输入的不是一个用户名,而是一段SQL语 ...
- python基础05--深浅copy, set,bytes
1.1 深浅 copy 1. = 赋值操作, lis1=[1,2,3] list2 = list1 list1.append(4) 则list1,list2都变 赋值都指向同一个地址,改变一个 ...
- Java自学-接口与继承 默认方法
默认方法 步骤 1 : 什么是默认方法 默认方法是JDK8新特性,指的是接口也可以提供具体方法了,而不像以前,只能提供抽象方法 Mortal 这个接口,增加了一个默认方法 revive,这个方法有实现 ...
- 【转】Webpack 快速上手(中)
由于文章篇幅较长,为了更好的阅读体验,本文分为上.中.下三篇: 上篇介绍了什么是 webpack,为什么需要 webpack,webpack 的文件输入和输出 中篇介绍了 webpack 在输入和输出 ...
- vue项目打包采坑
1. vue项目打包采坑 1.1. vue运行报错error:Cannot assign to read only property 'exports' of object '#' 这个错误我是在打包 ...
- 为什么Audition CC2017扫描不了电音插件,你需要这个工具
一时兴起,我也去下载并安装了Audition的音频后期处理软件,版本是cc2017.简单熟悉了对自己声音修理外,我还想添加一点电音的效果显得洋气一些.在网上下载并安装了warves tune后,发现A ...
- Centos 6.5 实战-MySQL定时增量备份(2)
首先在进行增量备份之前需要查看一下配置文件,查看 log_bin 是否开启,因为要做增量备份首先要开启 log_bin .首先,进入到 myslq 命令行,输入如下命令: [root@localhos ...
- HTTP状态码面试必知
typora-root-url: ./HTTPCODE HTTP状态码必知必会 这里主要介绍运维过程中经常遇到的状态码.并通过业界流行的Nginx进行模拟实现,让大家能有一种所见即所得的感觉.希望大家 ...