P3188 [HNOI2007]梦幻岛宝珠

梦幻岛宝珠

超大价值和体积的 0/1 背包,但保证每个体积都能写成 \(a\times 2^b,a\leq 10,b\leq 30\) 的形式。

远古省选的神仙题!

性质是一定要用到的,将所有体积按照 \(b\) 分量后分别做一次背包,设 \(f(i,j)\) 表示第 \(i\) 类,\(\sum a\leq j\) 的最大价值。

然后就比较难想了,设 \(g(i,j)\) 表示总体积不大于 \(j\times 2^i+(m\&(1<<i)-1)\),的最大价值。

即除了第 \(i\) 位二进制位之外都满足 \(\leq m\) 的限制的最大价值,因为后面那个东西等于 \(m\)\(i-1\) 位二进制位的值。

那么显然 \(Ans=g(p,1)\)\(p\)\(m\) 的最高二进制位,关键是转移方程:

\[f(i,j)=f(i,j-k)+g(i-1,(k<<1)+(m>>(i-1)\&1)) \]

什么意思,首先枚举的 \(k\) 表示之前的总价值相当于 \(k\times 2^i\),然后现在用了 \(j-k\)\(2^i\)

显然 \(g(i,j)\)\(i\) 相等的情况下,随着 \(j\) 增大,总价值不减,所以选择的决策也要尽量大。

那么如果 \(m\) 的第 \(i-1\) 位为 \(1\) 的话,就可以 \(+1\),因为状态只需要之前的 \(i-1\)\(\leq m\),所以这样会得到更优的值。

记得状态设计时都带有 \(\leq\) 的字样,所以初始化不能设 \(-\inf\),而是直接全部赋 \(0\)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;

#define V first
#define W second
#define MP make_pair
#define PB push_back
typedef pair<int, int> PII;

const int N = 35;
const int M = 1010;
int n, m, f[N][M], g[N][M];
vector<PII> G[N];

int read(){
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}

int main(){
	while((n = read()) + (m = read()) != -2){
		for(int i = 0; i < 31; i ++) G[i].clear();
		memset(f, 0, sizeof(f));
		memset(g, 0, sizeof(g));
		
		for(int i = 1; i <= n; i ++){
			int a = read(), w = read();
			int p = 31;
			while(a % (1 << (-- p)));
			G[p].PB(MP(a / (1 << p), w));
		}
		
		int p = 31;
		while(m < (1 << (-- p)));
		
		for(int t = 0; t <= p; t ++)
			for(int i = 0; i < (int) G[t].size(); i ++)
				for(int j = 10 * (int) G[t].size(); j >= G[t][i].V; j --)
					f[t][j] = max(f[t][j], f[t][j - G[t][i].V] + G[t][i].W);
		
		for(int i = 0; i <= 10 * (int) G[0].size(); i ++)
			g[0][i] = f[0][i];
		for(int i = 1; i <= p; i ++)
			for(int j = 0; j <= n * 10; j ++)
				for(int k = 0; k <= j; k ++)
					g[i][j] = max(g[i][j], g[i - 1][min(n * 10, 2 * k + (m >> (i - 1) & 1))] + f[i][j - k]);
		
		printf("%d\n", g[p][1]);
	}
	return 0;
}
posted @ 2021-07-20 20:00  LPF'sBlog  阅读(55)  评论(0编辑  收藏  举报