[dp+bitset]数的种类
题目大意
给定$n(n\le5\times10^{3})$个整数,问由这些整数通过“加法”操作,可以组成多少种数字?
其中,对于每个数$a_i$,$1\le a_{i}\le100$
初步思路
首先,暴力dfs
肯定是不能通过的,我们可以考虑用存在性dp来解决。
存在性dp,即我们只需考虑这个状态是否能够实现,即用0/1来代替。
先考虑最基本的,我们假设$dp[i][j]$为到第$a_i$个数位置能否组成$j$。然后考虑转移方程,首先$dp[i-1][j]$为$1$的情况那么$dp[i][j]$肯定能达到,在当前基础上$j+a_i$的数值也能达到。
例如:$i-1$之前可以组成$1,2,3$,$a_i=2$,则对于$i$之前,$3,4,5$一定也可以达到。因此,我们借助倒推回去的思想可以得到状态转移方程:
$$dp[i][j]=(dp[i-1][j-a_i]|dp[i][j])$$
之所以要用或运算,是因为这两个状态只要其中一个为$1$就可以了,而或运算则正好适用于这个情况。
而这时候的空间复杂度为$5\times10^{3}\times5\times10^{3}\times100$,显然是过不了的
进一步思考
对于到$a_i$这一维度,其实是可以直接省掉的,以此来节省空间,但是对于时间复杂度来说,依然是过不了的。接下来,我们就可以用到$\texttt{bitset}$这个东西了。
$\texttt{bitset}$可以当作有很多二进制的集合,只支持位运算,而不支持加减乘除,支持随机访问。
$\texttt{bitset}$常用函数
.count()
统计1的数量.reset()
全部重置为0
以上的时间复杂度均为$O(n)$
解题
假设从左到右分别代表$…,3,2,1,0$能否组成,当前状态$\texttt{s}$为$11$,$a_i=1$,只需要将当前状态先左移1位变成$110$,再或起来变成$111$即代表能组成$2,1,0$($\texttt{Tips:}$从右往左为低位到高位)。显然达到了我们的需求,假如$a_i=5$,只需要左移5位再或起来即可。
因此,我们可以得到转移方程:
$$dp=dp|(dp<<a_i)$$
其中$\texttt{dp}$用$\texttt{bitset}$表示,故代码如下:
1 |
|