题解 物品

传送门

数据范围很大,肯定不能直接背包

考虑一个类似梦幻岛宝珠的做法
限制是加在体积上的,那么对物品二进制分组,将 \(2^i\) 个物品绑成一个
那么从低到高逐位做背包,每一位继承上一位的结果
注意继承的时候只继承上一位与 \(L\) 的上一位的结果

复杂度 \(O(能过)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f3f3f3f3f
#define N 610
#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 m, L;
map<int, int> mp;
const int dlt=N*N;
vector<int> sta[60];
int f[2][N*N*2], now;
#define f(a, b) f[a][(b)+dlt]

signed main()
{
	freopen("goods.in", "r", stdin);
	freopen("goods.out", "w", stdout);

	m=read(); L=read();
	for (int i=-m; i<=m; ++i) mp[i]=read();
	// for (int i=-m; i<=m; ++i) mp[i*(L<0?-1:1)]=read();
	// L=llabs(L);
	for (auto it:mp) {
		int tem=it.sec;
		for (int i=0; tem>=1ll<<i; ++i)
			sta[i].pb(it.fir), tem-=1ll<<i;
		for (int i=0; tem>=1ll<<i; ++i) if (tem&(1ll<<i))
			sta[i].pb(it.fir);
	}
	memset(f, 128, sizeof(f));
	f(now, 0)=0;
	ll l=0, r=0, tl=0, tr=0;
	for (int i=0; i<=40; ++i,now^=1) {
		// cout<<"i: "<<i<<endl;
		// cout<<"sta: "; for (auto it:sta[i]) cout<<it<<' '; cout<<endl;
		for (auto it:sta[i]) {
			// cout<<"add: "<<it<<endl;
			// cout<<"---before---"<<endl;
			// memcpy(f[now^1], f[now], sizeof(f[now]));
			for (int j=tl; j<=tr; ++j) f(now^1, j)=f(now, j);
			for (int j=l; j<=r; ++j)
				f(now^1, j+it)=max(f(now^1, j+it), f(now, j)+(1ll<<i));
			l=min(l, l+it); r=max(r, r+it); now^=1;
			tl=l; tr=r;
		}
		// cout<<"id: "; for (int i=-L; i<=L; ++i) cout<<setw(3)<<i<<' '; cout<<endl;
		// cout<<"dp: "; for (int i=-L; i<=L; ++i) cout<<setw(3)<<f(now, i)<<' '; cout<<endl;
		// memset(f[now^1], 128, sizeof(f[now]));
		for (int j=tl; j<=tr; ++j) f(now^1, j)=-INF;
		bool tag=L&(1ll<<i);
		for (int i=l; i<=r; ++i) if ((i&1)==tag)
			f(now^1, i>>1)=max(f(now^1, i>>1), f(now, i));
		l>>=1; r>>=1;
	}
	// cout<<"dp: "; for (int i=-100; i<=100; ++i) cout<<setw(3)<<f(now, i)<<' '; cout<<endl;
	// cout<<(L>>41)<<endl;
	if (f(now, L>>41)<=0) puts("impossible");
	else printf("%lld\n", f(now, L>>41));

	return 0;
}
posted @ 2022-08-03 08:27  Administrator-09  阅读(1)  评论(0编辑  收藏  举报