您的位置:首页 > 其它

【bzoj3163】 HEOI2013Eden的新背包问题 多重背包

2015-08-07 12:36 363 查看
跪POPOQQQ神犇,一直在往容斥和2287的方向上想,虽然很明显不可行,其实只需要枚举左半边选多少右半边选多少就可以了,或者说的吊一点就是把左边看成一个泛化背包,右边看成一个泛化背包然后合并就好了。第一次写多重背包好激动呀!!!

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;

int a[1010],b[1010];
int w[1010],v[1010],c[1010];
int f[1010][1010],g[1010][1010];
int n,m=1000,T,l,r;

void insert(int x,int y)
{
	while (l<=r && b[r]<y) r--;
	b[++r]=y;a[r]=x;
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++) scanf("%d%d%d",&v[i],&w[i],&c[i]);
	memset(f,0,sizeof(f));
	for (int i=1;i<=n;i++)
	{
		if (c[i]*v[i]>m) c[i]=m/v[i];
		for (int d=0;d<v[i];d++)
		{
			l=1,r=0;
			for (int j=0;d+j*v[i]<=m;j++)
			{
				insert(j,f[i-1][d+j*v[i]]-j*w[i]);
				if (j-a[l]>c[i]) l++;
				f[i][d+j*v[i]]=b[l]+j*w[i];
			}
		}
	}
	memset(g,0,sizeof(g));
	for (int i=n;i>=1;i--)
	{
		for (int d=0;d<v[i];d++)
		{
			l=1,r=0;
			for (int j=0;d+j*v[i]<=m;j++)
			{
				insert(j,g[i+1][d+j*v[i]]-j*w[i]);
				if (j-a[l]>c[i]) l++;
				g[i][d+j*v[i]]=max(g[i+1][d+j*v[i]],b[l]+j*w[i]);
			}
		}
	}
	scanf("%d",&T);
	while (T--)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		x++;
		int ans=0;
		for (int i=0;i<=y;i++)
		  ans=max(ans,f[x-1][i]+g[x+1][y-i]);
		printf("%d\n",ans);
	}
	return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: