动态规划 存在性dp:数的种类

本文介绍了一种通过规划方法计算从零个到n个数字组合总数的算法,原问题使用二维布尔数组空间过大,通过一维简化并利用bitset数据结构,成功节省了大量内存。代码展示了如何用C++实现这一过程,以115为例演示操作。
摘要由CSDN通过智能技术生成


思路:这道题可以通过每一步的规划进而推出全局总共可以组成的数字的个数,即从取到零个数字为止可以组成一个数字0到取到n个数字为止可以组成m个数字,下图意为取到i个数字为止是否可以组成数字j,使用布尔型数组统计次数,1代表可以组成。当上一步可以组成的数字在下一步多取一个数时依然可以组成,并且在增加了a[i]这个数字后,第j+a[i]个也可以被组成(这时j的取值是上一步中所有为true的j范围)

但是使用二维bool型数组,空间会达到5e5的内存,空间太大,这时候将二维数组简化为一维,在原数组中进行复制和新增的操作,使用样例中三个数1 1 5进行演示

接下来做进一步简化,使用类似于数组的一个二进制结构bitset,只可以存放二进制数,可以大量节省空间

代码如下:

#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 5e3 + 9, M = 5e5 + 9;
int a[N];
void solve() {
	int n; cin >> n;
	for (int i = 1; i <=n; ++i)cin >> a[i];
	bitset<M>bs;
	bs[0] = 1;//最低位置为1,代表刚开始取零个数时,只可以组成0一个数的初始状态
	for (int i = 1; i <=n; i++) {
		bs |= (bs<< a[i]);//bs与bs-a[i]进行或操作,就可以同时进行复制与新增的操作,即把上一次的状态的复制过来,并且对在增加了a[i]后还可以组成哪些数进行标记,<<是位运算,相当于减
	}
	cout << bs.count() << '\n';//将数组中标记的个数输出
}
int main() {
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int _ = 1;
	while (_--)solve();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值