zoukankan      html  css  js  c++  java
  • FMT 和 子集卷积

    FMT 和 子集卷积

    FMT

    给定数列 $ a_{0dots 2^{k}-1} $ 求 $ b $ 满足 $ b_{s} = sum_{iin s} a_i $

    实现方法很简单,

    for( i in 0 to n-1 ) 
    	for( j in 0 to 2^n-1)
    		if( j & ( 1 << i ) ) 
    			a[j] += a[j ^ ( 1 << i )]
    

    然后称为 $ B = ext{FMT}(A) $ ,快速莫比乌斯变换

    想要还原也很简单,把代码反着写:

    for( i in n-1 downTo 0 ) 
    	for( j in 2^n - 1 downTo 0)
    		if( j & ( 1 << i ) ) 
    			a[j] -= a[j ^ ( 1 << i )]
    

    当然, $ i $ 的顺序可以是原来的顺序,因为按照哪个顺序枚举位根本不重要

    同时,$ j $ 的顺序也不重要,考虑对于一个数字,它只有在当前枚举的位数为 1 的时候才被执行,所以就算已经枚举到这位是 0 的状态,它也不会被更新。

    所以甚至只需要改个符号就是逆变换了

    for( i in 0 to n-1 ) 
    	for( j in 0 to 2^n-1)
    		if( j & ( 1 << i ) ) 
    			a[j] -= a[j ^ ( 1 << i )]
    

    这样 $ A = ext{IFMT}( B ) $

    FMT 可以写成 FFT 那样的形式,就不赘述了。

    或卷积

    或卷积就需要用到这个东西。

    或卷积是指:

    [C_s = sum_{i|j=s} A_i B_j ]

    有一个结论, $ ext{FMT}(C) = ext{FMT}(A) cdot ext{FMT}(B) $ ,其中 (cdot) 指点积,也就是把每个位置的函数值乘起来。

    原因是 ((i cup j) sube s) 等价于 ((i sube s)and(j sube s)) 。于是

    [egin{aligned} [x]FMT(C) &=sum_{s sube x}C_s\ &= sum_{s sube x}sum_{i|j = s}A_iB_j\ &= sum_{i|j sube x} A_iB_j\ &= ( sum_{isube x} A_i )(sum_{jsube x} B_j)\ &= [x]FMT(A) cdot [x]FMT(B) end{aligned} ]

    所以有 $ ext{FMT}(C) = ext{FMT}(A) cdot ext{FMT}(B) ) $

    于是可以 $ O(n2^n) $ 做这个。

    子集卷积

    子集卷积长这样:

    [C_s = A imes_{subset} B = sum_{i|j=s,i&j = 0} A_i B_j ]

    如果设 $ p(x) $ 为 $ x $ 的 popcount( 1 的个数),那么:

    [(i|j = s) , (i&j = 0) Leftrightarrow i|j = s , p(i)+p(j) = p(s)\C_s = sum_{i|j = s , p(i)+p(j) = p(s)} A_iB_j ]

    我们把 $ C $ 扩展到二维,设 $ C'_{x,k} $,定义如下:

    [C'_{x,s} = sum_{i|j = s,p(i)+p(j) = x} A_iB_j[p(s) = x] ]

    把 $ C $ 扩展到二维了,$ A $ 也扩展到二维,定义 $ A'_{p,s} $

    [A'_{x,s} = left{egin{aligned}&0 & {p(s) eq x}\&A_{s} & {p(s) = x} end{aligned} ight. ]

    同理定义 $ b'_{x,s} $

    我们知道

    [C'_{x,s} = sum_{i|j = s,p(i)+p(j) = x} A'_{p(i),i} B'_{p(j),j} ]

    观察到 $ C'x = sum{i=0}^x A'{i} imes{or} B'_{x-i} $ ,而且需要最后去掉左边的 $ p(s) eq x $ 的情况。

    这样复杂度 $ O(n^3 2^n) $,一共要卷 $ n^2 $ 次。

    注意 $ ext{FMT} , ext{IFMT} $ 都有可加性,所以我们把那个或卷积写成 $ ext{FMT} $ 的形式

    [egin{aligned}C'_{x} &= sum_i IFMT(FMT(A'_i) · FMT(B'_{x-i}))\&= IFMT( sum_i FMT(A_i') · FMT(B_{x-i}') )end{aligned} ]

    我们现在只需要处理出所有 $ A'i $ 和 $ B'{i} $ 的 FMT ,最后再跑 $ n $ 次逆 FMT ,所以这样做就优化到了 $ O( 2^n n^2 ) $

    不知道为啥 开O2 TLE 了。。。注意模数是 $ 10^9+9 $ 不是 $ 10^9+7 $。。。目害成功wa了两发

    #include "iostream"
    #include "algorithm"
    #include "cstring"
    #include "cstdio"
    using namespace std;
    #define P 1000000009
    int rd( ) {
        char ch = ' '; int ret = 0;
        while( ch > '9' || ch < '0' ) ch = getchar();
        while( ch >= '0' && ch <= '9' ) ret = ret * 10 + ch - '0' , ch = getchar();
        return ret;
    }
    
    int A[1<<21] , B[1<<21] , n , len;
    int a[21][1<<21] , b[21][1<<21] , c[21][1<<21];
    
    void FMT( int A[] , int l ) {
        for( int i = 0 ; i < l ; ++ i )
            for( int j = 0 ; j < ( 1 << l ) ; ++ j )
                if( j & ( 1 << i ) ) A[j] = ( A[j] + A[j ^ ( 1 << i )] ) % P;
    }
    void IFMT( int A[] , int l ) {
        for( int i = 0 ; i < l ; ++ i )
            for( int j = 0 ; j < ( 1 << l ) ; ++ j )
                if( j & ( 1 << i ) ) A[j] = ( A[j] + P - A[j ^ ( 1 << i )] ) % P;
    }
    
    int main() {
        cin >> n; len = ( 1 << n );
        for( int i = 0 ; i < len ; ++ i ) A[i] = rd() , a[__builtin_popcount(i)][i] = A[i];
        for( int i = 0 ; i < len ; ++ i ) B[i] = rd() , b[__builtin_popcount(i)][i] = B[i];
        for( int i = 0 ; i <= n ; ++ i ) FMT( a[i] , n ) ,  FMT( b[i] , n );
        for( int x = 0 ; x <= n ; ++ x ) {
            for( int i = 0 ; i <= x ; ++ i )
                for( int j = 0 ; j < ( 1 << n ) ; ++ j )
                    ( c[x][j] += 1ll * a[i][j] * b[x - i][j] % P ) %= P;
            IFMT( c[x] , n );
        }
        for( int i = 0 ; i < len ; ++ i ) printf("%d ",c[__builtin_popcount(i)][i]);
    }
    
  • 相关阅读:
    SSH 错误解决案例1:Read from socket failed: Connection reset by peer
    vmware已经全面支持open-vm-tools
    RHEL7.1 安装openstack juno 一个BUG
    web快速开发框架 WebBuilder 8.7发布
    2019年如何选择合适的快速开发平台和框架
    快速开发平台 WebBuilder 8.6发布
    快速开发平台比较
    快速开发平台 WebBuilder 8.4 发布
    快速开发平台 WebBuilder 8 发布
    快速开发平台WebBuilder中ExtJS表格的增删改查
  • 原文地址:https://www.cnblogs.com/yijan/p/12387352.html
Copyright © 2011-2022 走看看