题解 [HNOI2007] 梦幻岛宝珠

传送门

万年前的讲课题
现在还是不会做

考虑这个物品体积有什么性质
感觉上没什么性质,但发现有个 \(a\leqslant 10,n\leqslant 100\)
然后思考二进制分组的可行性
核心难点在于合并 \(2^i\)\(2^{i-1}\) 的答案
发现 \(2^{0\cdots i-1}\) 的总大小向上一层一层到了 \(i-1\) 这一层时总和 \(\leqslant 10n\)
而这个东西是可以接受的
那么可以令 \(f_{i, j}\) 为只考虑 \(2^i\) 这一层,\(\sum a=j\) 的最大答案
\(g_{i, j}\) 为考虑前 \(i\) 层,\((j-1)2^i<体积\leqslant j*2^i\) 时的最大答案
有转移

\[g_{i, j}=\max\limits_k(f_{i, j-k}+g_{i-1, \min(10n, 2k+[m\ 的第\ i-1\ 位为1])}) \]

可以精细处理一下上界

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
int w[N], sum[N];
vector<pair<int, int>> buc[32];
ll v[N], f[32][1000], g[32][1000];

signed main()
{
	while (1) {
		n=read(); m=read();
		if (n==-1&&m==-1) break;
		for (int i=1; i<=n; ++i) w[i]=read(), v[i]=read();
		memset(f, 0, sizeof(f));
		memset(g, 0, sizeof(g));
		for (int i=1; i<=31; ++i) buc[i].clear(), sum[i]=0;
		for (int i=1; i<=n; ++i) {
			for (int j=1; j<=10; ++j) if (w[i]%j==0 && __builtin_popcount(w[i]/j)==1) {
				buc[__builtin_ctz(w[i]/j)+1].pb({j, v[i]});
				sum[__builtin_ctz(w[i]/j)+1]+=j;
				// cout<<"("<<w[i]<<','<<v[i]<<") to "<<__builtin_ctz(w[i]/j)+1<<endl;
				break;
			}
		}
		for (int i=1; i<=31; ++i) sum[i]+=sum[i-1];
		for (int i=1; i<=31; ++i)
			for (auto it:buc[i])
				for (int j=sum[i]; j>=it.fir; --j)
					f[i][j]=max(f[i][j], f[i][j-it.fir]+it.sec); //, printf("f[%d][%d]=%lld\n", i, j, f[i][j]);
		for (int i=1; i<=31; ++i)
			for (int j=0; j<=sum[i]; ++j)
				for (int k=0; k<=j; ++k)
					g[i][j]=max(g[i][j], f[i][j-k]+g[i-1][min(sum[i-1], k*2+((m>>(max(0, i-2)))&1))]); //, printf("g[%d][%d]=%lld\n", i, j, g[i][j]);
		printf("%lld\n", g[32-__builtin_clz(m)][1]);
	}

	return 0;
}
posted @ 2022-06-08 20:33  Administrator-09  阅读(3)  评论(0编辑  收藏  举报