【每日一题】33. 简单瞎搞题 (滚动数组 + bitset 优化DP)

补题链接:Here

这个问题的难点在于如何统计出所有和可能出现的情况,并且不能重复。
很容易想到用桶去存储每一个数,即某个和能够组合出来则为1,否则为0

不妨令 \(dp[i][j]\) 表示为第 \(i\) 次选择时,和为 \(j\) 的情况是否出现过

但是内存方面需要 \(1e8\)\(int\) 内存,显然是不可接受的

那么我们考虑用 \(bitset\) 优化内存,由递推方程:\(dp_i = dp_{i}|=(dp_{i-1}<<(j*j))\)

代表第 \(i\) 次选择的时候是否能从当前状态转移到和为\(j\) 的状态

const int N = 110;
bitset<1000010>dp[N];
void solve() {
	int n; cin >> n;
	dp[0] = 1;
	for (int i = 1, l, r; i <= n; ++i) {
		cin >> l >> r;
		for (int j = l; j <= r; ++j)dp[i] |= (dp[i - 1] << (j * j));
	}
	cout << dp[n].count() << "\n";
}

写完状态转移方程发现 \(dp_i\) 仅与 \(dp_{i - 1}\) 有关系,所以由滚动数组来节省空间

bitset<1000010> now, nxt;
void solve() {
	int n; cin >> n;
	now[0] = 1;
	for (int i = 1, l, r; i <= n; ++i) {
		cin >> l >> r;
		for (int j = l; j <= r; ++j)
			if (j == l)nxt = (now << (j * j));
			else nxt |= (now << (j * j));
		now = nxt;
	}
	cout << now.count() << "\n";
}
posted @ 2021-05-25 19:08  RioTian  阅读(61)  评论(0编辑  收藏  举报