【学习笔记】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

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

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

FMT

基本思路:将二进制的每一位看成一维,枚举每一维做前缀和就可以得到集合的前缀和;

直接上代码了......

子集前缀和(= or)

for(int i=0;i>i&1)f[j]+=f[j^(1<

超集前缀和(= and)

for(int i=0;i=1<>i&1)f[j^(1<

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)\)

  • 【WC2018】州区划分

    #include
    #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<=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>i&1)
      for(int j=i+1;j>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>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<>1]+(i&1);
      }
      for(rg int i=0;i

转载于:https://www.cnblogs.com/Paul-Guderian/p/10826888.html

你可能感兴趣的:(【学习笔记】fwt&&fmt&&子集卷积)