Sum over Subsets(SOS) DP

一、引入

给出一个长度为\(2^n\)的数组\(A\),对于每一个\(mask< 2^n\)要求计算出\(f[mask]=\sum_{sub\in mask}A[sub]\)

(其中\(sub\in mask\)表示\(sub\&mask=sub\))

二、解法

1.暴力

for(int mask = 0; mask < (1<<n); mask++)
for(int sub = 0; sub <= mask; sub++)
if((sub & mask) == sub)
f[mask] += A[sub];

根据定义直接做,枚举所有小于\(mask\)的集合,判断\(sub\)是否是\(mask\)的子集

复杂度\(O(4^n)\)

2.子集枚举

for(int mask = 0; mask < (1<<n); mask++){
for(int sub = mask; ; sub = mask&(sub-1)){
f[mask] += A[sub];
if(!sub) break;
}
}

子集枚举优化之后

总复杂度是\(\sum_{m=0}^{n}C(n,m)\cdot 2^m = \sum_{m=0}^{n}C(n,m)\cdot 2^m\cdot 1^{n-m}=(1+2)^n\)

复杂度\(O(3^n)\)

3.SOSDP

考虑在计算当前的状态的\(f[mask]\)的时候,能否利用之前计算的结果来优化复杂度,并且不会重复计算

那就要定义新的状态:\(f[mask][bit]\)表示对于集合\(mask\),在子集\(sub\)和\(mask\)只有最后\(bit\)位存在不同的情况下的答案

可以发现\(f[mask][bit]= \begin{cases} A[mask] & bit=-1 \\ f[mask][bit-1] & mask\&(1<<bit)=0 \\ f[mask][bit-1]+f[mask \bigoplus (1<<bit)][bit-1] & mask\&(1<<bit)!=0 \end{cases}\)

当前位是\(1\)的情况下有两个分支,这个位置是\(1\)或者\(0\),并且从只改变之后的位的状态转移过来,能保证不重复

当前位是\(0\)的情况下这个位不能改变,所以只能选这位是\(0\)的之后的状态转换过来

空间压缩一下,代码如下

for(int mask = 0; mask < (1<<n); mask++) f[mask] = A[mask];
for(int bit = 0; bit < n; bit++)
for(int mask = 0; mask < (1<<n); mask++)
if(mask&(1<<bit)) f[mask] += f[mask^(1<<bit)];

复杂度\(O(n2^n)\)

考虑一下如何计算\(f[sub]=\sum_{sub \in mask} A[mask]\)

可以发现把所有集合取反,\(f[\overline{sub}] = \sum_{\overline{mask}\in \overline{sub}}A[\overline{mask}]\)

就相当于把\(0\)变成\(1\)来处理,代码基本相同

for(int mask = 0; mask < (1<<n); mask++) f[mask] = A[mask];
for(int bit = 0; bit < n; bit++)
for(int mask = 0; mask < (1<<n); mask++)
if(!(mask&(1<<bit))) f[mask] += f[mask^(1<<bit)]; // 只有这里的if改了

三、例题

  1. Codeforces165E 代码
  2. Codeforces383E 代码
  3. Codeforces449D 代码
  4. Codeforces1208F 代码
  5. Hdu5977 代码

参考CF博客

SOS DP学习笔记的更多相关文章

  1. 数位DP学习笔记

    数位DP学习笔记 什么是数位DP? 数位DP比较经典的题目是在数字Li和Ri之间求有多少个满足X性质的数,显然对于所有的题目都可以这样得到一些暴力的分数 我们称之为朴素算法: for(int i=l_ ...

  2. DP学习笔记

    DP学习笔记 可是记下来有什么用呢?我又不会 笨蛋你以后就会了 完全背包问题 先理解初始的DP方程: void solve() { for(int i=0;i<;i++) for(int j=0 ...

  3. 树形DP 学习笔记

    树形DP学习笔记 ps: 本文内容与蓝书一致 树的重心 概念: 一颗树中的一个节点其最大子树的节点树最小 解法:对与每个节点求他儿子的\(size\) ,上方子树的节点个数为\(n-size_u\) ...

  4. 斜率优化DP学习笔记

    先摆上学习的文章: orzzz:斜率优化dp学习 Accept:斜率优化DP 感谢dalao们的讲解,还是十分清晰的 斜率优化$DP$的本质是,通过转移的一些性质,避免枚举地得到最优转移 经典题:HD ...

  5. 动态 DP 学习笔记

    不得不承认,去年提高组 D2T3 对动态 DP 起到了良好的普及效果. 动态 DP 主要用于解决一类问题.这类问题一般原本都是较为简单的树上 DP 问题,但是被套上了丧心病狂的修改点权的操作.举个例子 ...

  6. [总结] 动态DP学习笔记

    学习了一下动态DP 问题的来源: 给定一棵 \(n\) 个节点的树,点有点权,有 \(m\) 次修改单点点权的操作,回答每次操作之后的最大带权独立集大小. 首先一个显然的 \(O(nm)\) 的做法就 ...

  7. 插头DP学习笔记——从入门到……????

    我们今天来学习插头DP??? BZOJ 2595:[Wc2008]游览计划 Input 第一行有两个整数,N和 M,描述方块的数目. 接下来 N行, 每行有 M 个非负整数, 如果该整数为 0, 则该 ...

  8. 树形$dp$学习笔记

    今天学习了树形\(dp\),一开始浏览各大\(blog\),发现都\(TM\)是题,连个入门的\(blog\)都没有,体验极差.所以我立志要写一篇可以让初学树形\(dp\)的童鞋快速入门. 树形\(d ...

  9. 斜率优化dp学习笔记 洛谷P3915[HNOI2008]玩具装箱toy

    本文为原创??? 作者写这篇文章的时候刚刚初一毕业…… 如有错误请各位大佬指正 从例题入手 洛谷P3915[HNOI2008]玩具装箱toy Step0:读题 Q:暴力? 如果您学习过dp 不难推出d ...

随机推荐

  1. Solon rpc 之 SocketD 协议 - 消息上报模式

    Solon rpc 之 SocketD 协议系列 Solon rpc 之 SocketD 协议 - 概述 Solon rpc 之 SocketD 协议 - 消息上报模式 Solon rpc 之 Soc ...

  2. 【转载】一种git commit前自动格式化的方式

    查看原文 简介 这个系列为了解决一个问题:自动化的去管理代码风格和格式 前提:Linux,C语言,Clang 如何在每次commit的时候,将代码风格自动格式化后再提交commit,且格式化的内容必须 ...

  3. 认识webservice

    1.为什么需要webservice? 目前还有很多商用程序继续在使用C++.Java.Visual Basic和其他各种各样的语言编写.现在,除了最简单的程序之外,所有的应用程序都需要与运行在其他异构 ...

  4. 【C++】《C++ Primer 》第十二章

    第十二章 动态内存 目前为止,所使用的对象都有着严格定义的生存期. 全局对象在程序启动时分配,在程序结束时销毁.局部自动对象在进入其定义所在的程序块时被创建,在离开块时销毁.局部static对象在第一 ...

  5. Linux学习笔记 | 配置Samba

    Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成.SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通 ...

  6. mysql中的基本注入函数

    1. 常见数据库注入函数: MYSQL: and length((user))>10 ACCESS: and (select count() from MSysAccessObject)> ...

  7. Python使用Protobuf&&如何赋值&&如何正反序列化

    前言 使用protobuf主要是两个步骤,序列化和反序列化. 关于Proto有哪些数据类型,然后如何编写,此处就不赘述了,百度一下有很多. 此文主要是总结,python使用protobuf的过程,如何 ...

  8. 简要MR与Spark在Shuffle区别

    一.区别 ①本质上相同,都是把Map端数据分类处理后交由Reduce的过程. ②数据流有所区别,MR按map, spill, merge, shuffle, sort, r educe等各阶段逐一实现 ...

  9. zabbix 监控tomcat

    zabbix 监控tomcat server端rpm -ivh jdk-8u20-linux-x64.rpmvi /etc/profileJAVA_HOME=/usr/java/jdk1.8.0_20 ...

  10. 【Docker】安装docker18.09.6后,无法启动

    ------------------------------------------------------------------------------------------------- | ...