[模拟赛][DP][背包][套路] Market

题面

在比特镇一共有 (n) 家商店,编号依次为 (1)(n)。每家商店只会卖一种物品,其中第 (i) 家商店的物品单价为 (c_i),价值为 (v_i),且该商店开张的时间为 (t_i)
(Byteasar) 计划进行 (m) 次购物,其中第 (i) 次购物的时间为 (T_i),预算为 (M_i)。每次购物的时候,(Byteasar) 会在每家商店购买最多一件物品,当然他也可以选择什么都不买。如果购物的时间早于商店开张的时间,那么显然他无法在这家商店进行购物。
现在 (Byteasar) 想知道,对于每个计划,他最多能购入总价值多少的物品。请写一个程序,帮助 (Byteasar) 合理安排购物计划。
注意:每次所花金额不得超过预算,预算也不一定要花完,同时预算不能留给其它计划使用

我们可以看到这个题除了容量十分之炫酷以外并没有别的问题
这时候就需要一个经典的套路:化价值为容量
(f[i]) 为达到 (i) 价值所需的最小容量
然后愉快 (DP) + 二分即可

// f[MAXN]  表示达到某个价值需要的容量
// 避免 1e9 的炫酷容量

# include <iostream>
# include <cstdio>
# include <cstring>
# include <algorithm>
# define MAXN 305
# define MAXM 1000005
# define co(x) mk[x].co
# define val(x) mk[x].val
# define optim(x) mk[x].optim

struct market{
	int co, val, optim;
}mk[MAXN];
struct query{
	int tim, mon;
	int id;
}qr[MAXM];
int f[MAXN*MAXN];
int ans[MAXM];

bool CmpM(market x, market y){
	return x.optim < y.optim;
}
bool CmpQ(query x, query y){
	return x.tim < y.tim;
}

int main(){
	int n, m;
	scanf("%d%d", &n, &m);

	for(int i = 1; i <= n; i++){
		scanf("%d%d%d", &co(i), &val(i), &optim(i));
	}

	for(int i = 1; i <= m; i++){
		scanf("%d%d", &qr[i].tim, &qr[i].mon);
		qr[i].id = i;
	}

	std::sort(mk+1, mk+n+1, CmpM);
	std::sort(qr+1, qr+m+1, CmpQ);
	memset(f, 0x3f, sizeof(f));

	f[0] = 0;

	int j = 1;
	for(int i = 1; i <= m; i++){
		while(j <= n && mk[j].optim <= qr[i].tim){
			for(int k = n * 300; k >= mk[j].val; k--){
				f[k] = std::min(f[k], f[k-mk[j].val] + mk[j].co);
			}
			for(int k = n * 300; k; k--){
				f[k] = std::min(f[k], f[k+1]);
			}
			j++;
		}
		ans[qr[i].id] = std::upper_bound(f+1, f+n*300+1, qr[i].mon) - f - 1;
	}

	for(int i = 1; i <= m; i++){
		printf("%d
", ans[i]);
	}

	return 0;
}
原文地址:https://www.cnblogs.com/Foggy-Forest/p/13681377.html