zoukankan      html  css  js  c++  java
  • [学习笔记] 高维前缀和

    算法用途

    [sum_{i = 0}^{n} [i & n = i] a_i ]

    (实际上, 这只是高维前缀和的一种特殊形式, 即每一维的大小都为 2.)


    算法过程

    我们计算矩阵前缀和时, 通常用的是容斥的方法.

    设当前要计算 (D) 维前缀和, 容斥的复杂度为

    [sum_{i = 0}^n inom{D}{i} = 2^D ]

    当维数过大时显然不行.


    我们考虑计算矩阵前缀和的另一种方法 : 先算出每一列的前缀和, 然后再把每一列的前缀和加起来即可得到一个矩阵的前缀和.

    我们来分析一下这个方法的实质 : 矩阵是一个二维结构, 我们用二元组 ((i,j)) 来表示矩阵上的点. 那么每一列的前缀和实质上是控制了 (j) 这一维后计算的前缀和, 而一个矩阵的前缀和就是 (i,j) 这两维都不进行控制的前缀和.

    考虑把这个方法推广到 (D) 维 : 先求出控制 前 (D) 维 的前缀和, 再求出控制 前 (D - 1) 维 的前缀和, 再求出控制 前 (D - 2) 维的前缀和 ...... 最终求出控制 前 (0) 维 的前缀和, 即为 (D) 维前缀和.

    用式子来表示就是 : 设 (sum[i][s]) 为控制了 前 (D - i) 维的点 (s) 的前缀和 (即​ (sum[i][s]) 内统计到的点的 前 (D - i) 维 都和 (s) 相同), 那么 (sum[i][s] = sum[i - 1][s] + sum[i][s']), 其中 (s') 为前 (i - 1) 维都与 (s) 相同 且 第 (i) 维比 (s)(1) 的点. 联想一下矩阵前缀和就很好理解了.


    代码实现

    由于在转移过程中, (s') 严格小于 (s), 所以 (sum) 的第一维可以用滚动数组优化.

    这里只给出了每一维的大小都等于 (2) 的情况的代码, 即「算法用途」中给出的形式.

    for (int i = 0; i < n; i++)
        for (int s = 0; s < 1 << n; s++)
            if (s >> i & 1) sum[s] += sum[s ^ (1 << i)];
    

    当然, 由于这里每一维的大小都为 (2), 所以你把中间那个循环的顺序反过来也行, 而更一般的情况下就要严格按照顺序转移了.


    有什么没看懂或者表达不严谨的地方欢迎留言

  • 相关阅读:
    单例模式的七种写法
    Android省电开发 浅析
    android省电开发之cpu降频
    什么是签名、为什么要给应用程序签名、如何给应用程序签名
    内存溢出和内存泄漏的区别、产生原因以及解决方案
    Android Studio 使用GitHub
    sharesdk 的使用
    当ViewPager嵌套在ScrollView/ListView里时,手势冲突如何处理?
    laravel安装笔记
    erlang的一些小技巧(不定期更新)
  • 原文地址:https://www.cnblogs.com/BruceW/p/13388096.html
Copyright © 2011-2022 走看看