3163: [Heoi2013]Eden的新背包问题

版权声明:菜鸡blog,随便转载 https://blog.csdn.net/qq_36808030/article/details/85982149

题意:

“寄没有地址的信,这样的情绪有种距离,你放着谁的歌曲,是怎样的心心静,能不能说给我听。”
失忆的Eden总想努力地回忆起过去,然而总是只能清晰地记得那种思念的感觉,却不能回忆起她的音容笑貌。 记忆中,她总是喜欢给Eden出谜题:在 valentine’s day 的夜晚,两人在闹市中闲逛时,望着礼品店里精巧玲珑的各式玩偶,她突发奇想,问了 Eden这样的一个问题:有n个玩偶,每个玩偶有对应的价值、价钱,每个玩偶都可以被买有限次,在携带的价钱m固定的情况下,如何选择买哪些玩偶以及每个玩偶买多少个,才能使得选择的玩偶总价钱不超过m,且价值和最大。众所周知的,这是一个很经典的多重背包问题,Eden很快解决了,不过她似乎因为自己的问题被飞快解决感到了一丝不高兴,于是她希望把问题加难:多次 询问,每次询问都将给出新的总价钱,并且会去掉某个玩偶(即这个玩偶不能被选择),再问此时的多重背包的答案(即前一段所叙述的问题)。
这下Eden 犯难了,不过Eden不希望自己被难住,你能帮帮他么?

题解:

感觉数据水的一匹。
直接多重背包+前后缀优化 O ( q e i ) O(qe_i) 就爆过去了。
code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
struct node{
	int a,b,c;
}a[1010];
int f[2][1010][1010],g[1010];
int n,q[1010],st,ed;
void add(int *f,int k)
{
	for(int i=0;i<a[k].a;i++)
	{
		st=1;ed=0;
		for(int j=i;j<=1000;j+=a[k].a)
		{
			while(st<=ed&&(j-q[st])/a[k].a>a[k].c) st++;
			while(st<=ed&&(j-q[ed])/a[k].a*a[k].b+g[q[ed]]<g[j]) ed--;
			q[++ed]=j;f[j]=(j-q[st])/a[k].a*a[k].b+g[q[st]];
		}
	}
}
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++) a[i].a=read(),a[i].b=read(),a[i].c=read();
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=1000;j++) g[j]=f[0][i-1][j];
		add(f[0][i],i);
	}
	for(int i=n;i>=1;i--)
	{
		for(int j=0;j<=1000;j++) g[j]=f[1][i+1][j];
		add(f[1][i],i);
	}
	int Q=read();
	while(Q--)
	{
		int x,d;x=read();d=read();x++;
		int ans=0;
		for(int i=0;i<=d;i++) ans=max(ans,f[0][x-1][i]+f[1][x+1][d-i]);
		printf("%d\n",ans);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_36808030/article/details/85982149