记录编号 444605 评测结果 AAAAAAAAAA
题目名称 [NOIP 2010冲刺二]宝物筛选 最终得分 100
用户昵称 Gravatarswttc 是否通过 通过
代码语言 C++ 运行时间 0.264 s
提交时间 2017-09-03 15:09:27 内存使用 17.87 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>

using namespace std;

int n,l,v[110],m[110],w[110],f[110][40010];

struct nodes
{
	int tim,large;
}q[100010];

int qh=1,qt=1;

int main()
{
	freopen("treasure.in","r",stdin);
	freopen("treasure.out","w",stdout);
	scanf("%d",&n);
	scanf("%d",&l);
	for(int i=1;i<=n;i++) scanf("%d%d%d",&v[i],&w[i],&m[i]);
	for(int i=1;i<=n;i++){
		for(int j=0;j<w[i];j++){
			qh=qt=1;
			for(int k=0;k*w[i]+j<=l;k++){
				int nl=f[i-1][k*w[i]+j]-k*v[i];
				while(q[qt-1].large<nl&&qh<qt){
					qt--;
				}
				q[qt].large=nl;
				q[qt].tim=k;
				qt++;
				while(q[qh].tim+min(m[i],k)<k){
					qh++;
				}
				f[i][k*w[i]+j]=q[qh].large+k*v[i];
			}
		}
	}
	printf("%d\n",f[n][l]);
	return 0;
}
/*
f[i][j]=max(f[i-1][j-k*w[i]]+k*v[i])(0<=k<=m[i])
因为j=j%w[i]+j/w[i]*w[i]
得出f[i][j]=max(f[i-1][j%w[i]+j/w[i]*w[i]-k*w[i]]+k*v[i])(0<=k<=m[i]) 
设a=j%w[i],b=j/w[i]-k
则k=j/w[i]-b
f[i][j]=max(f[i-1][a+b*w[i]]+(j/w[i]-b)*v[i])(j/w[i]-m[i]<=b<=j/w[i])
对每个等式右侧减去(j/w[i])*v[i]再加上(j/w[i])*v[i]
f[i][j]=max(f[i-1][a+b*w[i]]-b*v[i])+(j/w[i])*v[i](j/w[i]-m[i]<=b<=j/w[i])
把循环改为枚举i,a,j/w[i]
于是对于每个j求出当j/w[i]-m[i]<=b<=j/w[i]时f[i-1][a+b*w[i]]-b*v[i]中的最大值
即可以使用单调队列在O(1)求出 
*/