[模拟赛][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\n", ans[i]);
	}

	return 0;
}
posted @ 2020-09-16 20:58  ChPu437  阅读(94)  评论(0编辑  收藏  举报