题解 物品
数据范围很大,肯定不能直接背包
考虑一个类似梦幻岛宝珠的做法
限制是加在体积上的,那么对物品二进制分组,将 \(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;
}