P3891 [GDOI2014]采集资源

大致题意

\(m\)块钱,\(n\)种苦工,每个苦工都有一个购入值\(a_i\)和每秒收入\(b_i\),求让总钱数达到\(t\)的最少时间

\(n≤100,m,t≤1000, a_i,b_i≤2^{31}\)

分析

考虑到每秒钟的决策和花费金钱数及当前每秒收入量有关,且这里的每秒收入量数值较大,不妨设\(f(i,j)\)表示在前\(i\)秒总钱数为\(j\)时的每秒收入量

设该秒花费的钱数为\(k\),花\(k\)元钱能买到的最大收入量为\(v_k\),有显然的转移:

$f(i,j) = max(f(i-1,j+k-f(i-1,j+k)-v_k)+v_k)$

总钱数达到\(t\)时输出\(i\)即可

小坑点:初始钱数大于t时直接输出0

//xcxc82 2021/7/30
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1010;
inline int read(){
	int X=0; bool flag=1; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
	while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
	if(flag) return X;return ~(X-1);
}
int n,m,t;
int a[MAXN],b[MAXN];
int f[MAXN][MAXN],g[MAXN];
int main(){
	n = read(),m = read(),t = read();
	if(m>=t){
		cout<<0<<endl;
		return 0;
	}
	for(int i=1;i<=n;i++){
		a[i] =read(),b[i] = read();
	}
	memset(f,-1,sizeof(f));
	memset(g,-1,sizeof(g));
	g[0] = 0,f[0][m] = 0;
	for(int i=0;i<=n;i++){
		for(int j=a[i];j<=1000;j++){
			g[j] = max(g[j],g[j-a[i]]+b[i]);
		}
	}
	for(int i=0;i<=1000;i++){
		for(int j=0;j<=t;j++){
			if(f[i][j]!=-1)
			for(int k=0;k<=j;k++){
				f[i+1][j-k+g[k]+f[i][j]] = max(g[k]+f[i][j],f[i+1][j-k+g[k]+f[i][j]]);
				if(j-k+g[k]+f[i][j]>=t){
					cout<<i+1;
					return 0;
				}
			}
		}
	}
}

重构于2021/7/30

posted @ 2020-09-29 22:42  xcxc82  阅读(113)  评论(0编辑  收藏  举报