zoukankan      html  css  js  c++  java
  • Note -「SOS DP」高维前缀和

    本文差不多算是翻译了一遍 CF blog?id=45223 就是抄了一遍,看不懂可以去原文。

    当然我的翻译并不是完全遵从原文的。

    Part. 1 Introduction

    平时我们怎么求高维前缀和?容斥对吧,复杂度多少?(mathcal{O}(n^{d} imes2^{d}))(n) 每维元素个数,默认同阶,(d) 维度)。

    这好吗?这不好。

    Part. 2 Ying Wen

    For 个 example,二维,容斥这么写对吧?

    for(int i=1;i<=n;i++)
    {
      for(int j=1;j<=n;j++)  f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+a[i][j];
    }
    

    事实上我们还可以分维来前缀和:

    for(int i=1;i<=n;i++)
    {
      for(int j=1;j<=n;j++)  f[i][j]=f[i-1][j]+a[i][j];
    }
    for(int i=1;i<=n;i++)
    {
      for(int j=1;j<=n;++j)  f[i][j]=f[i][j-1]+a[i][j];;
    }
    

    复杂度多少?(mathcal{O}(n^{d} imes d)),厉害吧。

    对应到 SOS DP(sum over subsets),我们把每一维整到集合上去来求子集和。

    形式化地定义子集和,即给定一个有 (2^{n}) 个元素的数组 (A),定义函数:

    [ ext{sub-sum}(mask)=sum_{isubseteq mask}A_{i} ]

    写成位运算的形式:

    [ ext{sub-sum}(mask)=sum_{mask ext{ & }i=i}A_{i} ]

    学过 FWT 的巨佬可能发现了什么,可是这和我没关系。

    看不懂?没关系,我们有严谨的代码定义:

    for(int mask = 0;mask < (1<<N); ++mask){
    	for(int i = 0;i < (1<<N); ++i){
    		if((mask&i) == i){
    			F[mask] += A[i];
    		}
    	}
    }
    

    这是什么垃圾复杂度,用高维前缀和可得以下代码:

    for (int j = 0; j < n; ++j) {
      for (int i = 0; i < (1 << n); ++i) {
        if((i >> j) & 1)  f[i] += f[i ^ (1 << j)];
      }
    }
    
  • 相关阅读:
    UVA-11437 Triangle Fun
    UVA 10491
    CF 223C
    poj 3273
    由异常掉电问题---谈xfs文件系统
    好久没有写博客了,最近一段时间做一下总结吧!
    Json.Net
    div 旋转
    VirtualBox虚拟机网络设置
    windows 2003 安装 MVC 环境 404错误,无法找到该页
  • 原文地址:https://www.cnblogs.com/orchid-any/p/14636647.html
Copyright © 2011-2022 走看看