位运算卷积
有点错,原来 or 和 and 的卷积叫 FMT,xor 的卷积叫 FWT。我之前学的是什么东西。
or 卷积
集合并乘法:。
设 ,也就是高维前缀和。 就是高维差分。
有 和 。
and 卷积 则是向低维去前缀和?
这两个卷积根本就不用递归。
xor 卷积
设 。然后可以递归:。
void fmtor(int *a,int n,int w=1){
for(int i=0;i<n;i++){
for(int s=0;s<(1<<n);s++)if(s&(1<<i))(a[s]+=a[s^(1<<i)]*w)%=mod;
}
}
void fmtand(int *a,int n,int w=1){
for(int i=0;i<n;i++){
for(int s=0;s<(1<<n);s++)if(s&(1<<i))(a[s^(1<<i)]+=a[s]*w)%=mod;
}
}
void fwtxor(int *a,int n,int fl=1){
for(int l=2;l<=n;l<<=1){
int k=l>>1;
for(int i=0;i<n;i+=l){
for(int j=i;j<i+k;j++){
int u=a[j],v=a[j+k];
a[j]=(u+v)*fl%mod,a[j+k]=(u+mod-v)*fl%mod;
}
}
}
}
int f[1<<17],g[1<<17];
void mulor(int *a,int *b,int *ans,int n){
for(int i=0;i<(1<<n);i++)f[i]=a[i],g[i]=b[i];
fmtor(f,n),fmtor(g,n);
for(int i=0;i<(1<<n);i++)(f[i]*=g[i])%=mod;
fmtor(f,n,mod-1);
for(int i=0;i<(1<<n);i++)ans[i]=f[i],f[i]=g[i]=0;
}
void muland(int *a,int *b,int *ans,int n){
for(int i=0;i<(1<<n);i++)f[i]=a[i],g[i]=b[i];
fmtand(f,n),fmtand(g,n);
for(int i=0;i<(1<<n);i++)(f[i]*=g[i])%=mod;
fmtand(f,n,mod-1);
for(int i=0;i<(1<<n);i++)ans[i]=f[i],f[i]=g[i]=0;
}
void mulxor(int *a,int *b,int *ans,int n){
for(int i=0;i<(1<<n);i++)f[i]=a[i],g[i]=b[i];
fwtxor(f,1<<n),fwtxor(g,1<<n);
for(int i=0;i<(1<<n);i++)(f[i]*=g[i])%=mod;
fwtxor(f,1<<n,(mod+1)/2);
for(int i=0;i<(1<<n);i++)ans[i]=f[i],f[i]=g[i]=0;
}
子集卷积
集合无交并乘法:。
等价于 ,所以取 ,则 。也称为占位多项式。
也即拆为 个集合幂级数,集合幂级数做集合并乘法,集合幂级数间看做形式幂级数做加乘卷积。
逆着做形式幂级数部分就是 求逆。
exp & ln
弄出占位幂级数,对集合幂级数一维 fmt,对形式幂级数一维做 ln 和 exp。
泰勒展开:。所以有 和 。
把 当成集合幂级数,设 ,则 ,其中乘法为无交并。exp 的组合意义即有序取 个子集再消除顺序,可以对应到 枚举子集的卷积 。ln 则为其逆运算。
Code
void fmt(int *a,int n,int w=1){
for(int i=0;i<n;i++){
for(int s=0;s<(1<<n);s++)if(s&(1<<i))(a[s]+=a[s^(1<<i)]*w)%=mod;
}
}
int ff[maxn+1][1<<maxn],gg[maxn+1][1<<maxn],hh[1<<maxn],ni[maxn+1];
void xormul(int *a,int *b,int *c,int n){//a*b=c
for(int i=0;i<=n;i++){
for(int s=0;s<(1<<n);s++)ff[i][s]=gg[i][s]=0;
}
for(int s=0;s<(1<<n);s++)ff[__builtin_popcount(s)][s]=a[s];
for(int s=0;s<(1<<n);s++)gg[__builtin_popcount(s)][s]=b[s];
for(int i=0;i<=n;i++)fmt(ff[i],n,1);
for(int i=0;i<=n;i++)fmt(gg[i],n,1);
for(int s=0;s<(1<<n);s++){
for(int i=0;i<=n;i++){
hh[i]=0;
for(int j=0;j<=i;j++)(hh[i]+=ff[j][s]*gg[i-j][s])%=mod;
}
for(int i=0;i<=n;i++)ff[i][s]=hh[i];
}
for(int i=0;i<=n;i++)fmt(ff[i],n,mod-1);
for(int s=0;s<(1<<n);s++)c[s]=ff[__builtin_popcount(s)][s];
}
void xordiv(int *a,int *b,int *c,int n){//a/b=c
for(int i=0;i<=n;i++){
for(int s=0;s<(1<<n);s++)ff[i][s]=gg[i][s]=0;
}
for(int s=0;s<(1<<n);s++)ff[__builtin_popcount(s)][s]=a[s];
for(int s=0;s<(1<<n);s++)gg[__builtin_popcount(s)][s]=b[s];
for(int i=0;i<=n;i++)fmt(ff[i],n,1);
for(int i=0;i<=n;i++)fmt(gg[i],n,1);
for(int s=0;s<(1<<n);s++){
int nig=ksm(gg[0][s]);
for(int i=0;i<=n;i++){
hh[i]=ff[i][s];
for(int j=1;j<=i;j++)(hh[i]+=mod-gg[j][s]*hh[i-j]%mod)%=mod;
hh[i]=hh[i]*nig%mod;
}
for(int i=0;i<=n;i++)ff[i][s]=hh[i];
}
for(int i=0;i<=n;i++)fmt(ff[i],n,mod-1);
for(int s=0;s<(1<<n);s++)c[s]=ff[__builtin_popcount(s)][s];
}
void xorni(int *a,int *b,int n){//b=1/a
for(int i=0;i<=n;i++){
for(int s=0;s<(1<<n);s++)ff[i][s]=0;
}
for(int s=0;s<(1<<n);s++)ff[__builtin_popcount(s)][s]=a[s];
for(int i=0;i<=n;i++)fmt(ff[i],n,1);
for(int s=0;s<(1<<n);s++){
int nif=ksm(ff[0][s]);
for(int i=0;i<=n;i++){
hh[i]=1;
for(int j=1;j<=i;j++)(hh[i]+=mod-ff[j][s]*hh[i-j]%mod)%=mod;
hh[i]=hh[i]*nif%mod;
}
for(int i=0;i<=n;i++)ff[i][s]=hh[i];
}
for(int i=0;i<=n;i++)fmt(ff[i],n,mod-1);
for(int s=0;s<(1<<n);s++)b[s]=ff[__builtin_popcount(s)][s];
}
void xorln(int *a,int *b,int n){//exp(a)=b
for(int i=0;i<=n;i++){
for(int s=0;s<(1<<n);s++)ff[i][s]=0;
}
for(int s=0;s<(1<<n);s++)ff[__builtin_popcount(s)][s]=a[s];
for(int i=0;i<=n;i++)fmt(ff[i],n,1);
for(int s=0;s<(1<<n);s++){
for(int i=0;i<n;i++){
hh[i]=ff[i+1][s]*(i+1)%mod;
for(int j=1;j<=i;j++)(hh[i]+=mod-ff[j][s]*hh[i-j]%mod)%=mod;
}
for(int i=1;i<=n;i++)ff[i][s]=hh[i-1]*ni[i]%mod;
}
for(int i=1;i<=n;i++)fmt(ff[i],n,mod-1);
b[0]=0;for(int s=0;s<(1<<n);s++)b[s]=ff[__builtin_popcount(s)][s];
}
void xorexp(int *a,int *b,int n){//ln(a)=b
for(int i=0;i<=n;i++){
for(int s=0;s<(1<<n);s++)ff[i][s]=0;
}
for(int s=0;s<(1<<n);s++)ff[__builtin_popcount(s)][s]=a[s];
for(int i=0;i<=n;i++)fmt(ff[i],n,1);
for(int s=0;s<(1<<n);s++){
for(int i=0;i<n;i++){
hh[i]=ff[i+1][s]*(i+1)%mod;
for(int j=1;j<=i;j++)(hh[i]+=ff[j][s]*j%mod*hh[i-j]%mod*ni[i-j+1])%=mod;
}
for(int i=1;i<=n;i++)ff[i][s]=hh[i-1]*ni[i]%mod;
}
for(int i=1;i<=n;i++)fmt(ff[i],n,mod-1);
b[0]=1;for(int s=1;s<(1<<n);s++)b[s]=ff[__builtin_popcount(s)][s];
}