jzoj100044-abcd【多重背包,二进制压缩,dp】

版权声明:原创,未经作者允许禁止转载 https://blog.csdn.net/Mr_wuyongcong/article/details/85014240

正题


题目大意

给出长度为 n n 的序列 a , b , c , d a,b,c,d
求一个序列 e e 满足
( i = 1 n e i c i ) = 0 ( e [ a i . . b i ] ) (\sum _{i=1}^ne_i*c_i)=0(e\in [a_i..b_i])

m a x { i = 1 n e i d i } max\{\sum_{i=1}^ne_i*d_i\}


解题思路

我们把这个转换成一个多重背包问题,拿 a i b i a_i\sim b_i 个物品,要求价格之和为 0 0 ,且价值最大。
我们可以发现对于每个物品我们都至少 a i a_i 个,所有我们可以直接把 a i a_i 个丢进背包里,然后每个物品数量变为 b i a i b_i-a_i 个,做多重背包。
要二进制压缩,不然会 T T


c o d e code

#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 210
using namespace std;
int n,m,tmp,num;
int a[N],b[N],c[N],d[N];
int w[10050],v[10050],f[100050];
int main()
{
	memset(f,0xcf,sizeof(f));f[0]=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
	    scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
	    b[i]-=a[i];tmp+=a[i]*d[i];m-=a[i]*c[i];
	}
	for(int k=1;k<=n;k++)//二进制压缩
	{
		for(int i=1;i<=b[k];i*=2)
		{
			w[++num]=c[k]*i;v[num]=d[k]*i;
			b[k]-=i;
		}
		if(b[k]) w[++num]=b[k]*c[k],v[num]=d[k]*b[k];
	}
	for(int i=1;i<=num;i++)//背包
	  for(int j=m;j>=w[i];j--)
	    f[j]=max(f[j],f[j-w[i]]+v[i]);
	printf("%d",f[m]+tmp);
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/85014240