题目链接
这可不是瞎搞,出题人是有bear来。查资料时遇见的例题,当练习写一下。做法是位运算bitset优化的背包。
思路:
相当于有 n n n 组,每组选一个物品,然后问最后得到的重量之和是多少。不看位运算优化的话,和这个D题有点像。
朴素想法是设 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示能否取得前 i i i 组,重量之和为 j j j 的状态, d p dp dp 值是个 b o o l bool bool 表示能否取到这个状态。但是这样重量可以是 1 0 6 10^6 106 的,组数是 100 100 100,运算次数 100 ∗ 100 ∗ 1 0 6 = 1 0 10 100*100*10^6=10^{10} 100∗100∗106=1010 ,时间空间都过不去。
我们不用 b o o l bool bool 值来存储状态,而是用一个二进制位来存储。这样就可以写成 b i t s e t < 1000001 > d p [ i ] bitset<1000001> dp[i] bitset<1000001>dp[i] , d p [ i ] [ j ] dp[i][j] dp[i][j] 仍然可以表示和上面同样的意义,但是这时我们可以使用位运算,空间还只有原来的 1 64 \frac1{64} 641,运算次数变成 2 ∗ 1 0 8 2*10^8 2∗108 不到,反正卡过去了。
第一维还能滚动优化。
code:
#include <iostream>
#include <cstdio>
#include <bitset>
using namespace std;int n;
bitset<1000001> dp[2];int main(){cin>>n;dp[0]=1;for(int i=1,l,r;i<=n;i++){cin>>l>>r;auto &pre=dp[(i-1)&1],&t=dp[i&1];t.reset();for(int x=l;x<=r;x++){t|=pre<<x*x;}}cout<<dp[n&1].count();return 0;
}