Market

Problem B. Market(market.c/cpp/pas)
Input file: market.in
Output file: market.out
Time limit: 1 seconds
Memory limit: 128 megabytes
在比特镇一共有n 家商店,编号依次为1 到n。每家商店只会卖一种物品,其中第i 家商店的物品
单价为ci,价值为vi,且该商店开张的时间为ti。
Byteasar 计划进行m 次购物,其中第i 次购物的时间为Ti,预算为Mi。每次购物的时候,Byteasar
会在每家商店购买最多一件物品,当然他也可以选择什么都不买。如果购物的时间早于商店开张的时间,
那么显然他无法在这家商店进行购物。
现在Byteasar 想知道,对于每个计划,他最多能购入总价值多少的物品。请写一个程序,帮助
Byteasar 合理安排购物计划。
注意:每次所花金额不得超过预算,预算也不一定要花完,同时预算不能留给其它计划使用。
Input
第一行包含两个正整数n;m,表示商店的总数和计划购物的次数。
接下来n 行,每行三个正整数ci; vi; ti,分别表示每家商店的单价、价值以及开张时间。
接下来m 行,每行两个正整数Ti;Mi,分别表示每个购物计划的时间和预算。
Output
输出m 行,每行一个整数,对于每个计划输出最大可能的价值和。
Examples
market.in 
5 2
5 5 4
1 3 1
3 4 3
6 2 2
4 3 2
3 8

5 9

market.out

10
12
第一个计划可以在商店2,3,5 各购买一件物品,总花费为1 + 3 + 4 = 8,总价值为3 + 4 + 3 = 10。

第二个计划可以在商店1,2,3 各购买一件物品,总花费为5 + 1 + 3 = 9,总价值为5 + 3 + 4 = 12。


题解

60%

先把查询排序,然后边做背包边回答(最后再排回去)

f[i][j]表示的是考虑了前i个商店,花费小于等于j

复杂度O(NM)

100%

看了题解才会的。。

我们发现对于后40%的数据,c[i](花费)很大但v[i](获得的价值)很小,于是修改状态为:

f[i][j]表示考虑了前i个商店,获利恰好为j时,所用的最小化费(初始设为正无穷)

方程f[i][j]=min(f[i-1][j],f[i-1][j-v[i]]+c[i])

于是对于每一个询问M,直接从后往前扫描,找到第一个小于等于M的值,其下标就是答案

复杂度O(N*N*v[max])

这里这么设置主要是因为考虑到60%时候的方程,当M变大时,v依然很小,于是考虑把下标和数组的值更换一下位置

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 310
#define maxv 90000
#define inf ((long long)1<<60)
#define ll long long
using namespace std;
ll f[maxv+100], n, m;
struct quiry
{
	ll M, T, num, ans;
	bool operator<(quiry x)const{return T==x.T?M>x.M:T<x.T;}
}q[100010];
struct item
{
	ll c, v, t;
	bool operator<(item x)const{return t<x.t;}
}it[350];
void init()
{
	ll i, j;
	scanf("%lld%lld",&n,&m);
	for(i=1;i<=n;i++)scanf("%lld%lld%lld",&it[i].c,&it[i].v,&it[i].t);
	for(i=1;i<=m;i++)scanf("%lld%lld",&q[i].T,&q[i].M),q[i].num=i;
	sort(it+1,it+n+1);sort(q+1,q+m+1);
}
void work()
{
	ll i, j, k, t, l, r, mid;
	quiry *p;
	for(i=1;i<=maxv;i++)f[i]=inf;
	for(p=q+1;p->T<it[1].t;p++)p->ans=0;
	for(i=1,it[n+1].t=inf;i<=n;i++)
	{
		for(j=maxv;j>=it[i].v;j--)f[j]=min(f[j],f[j-it[i].v]+it[i].c);
		for(;p->T<it[i+1].t and p->num<=m;p++)
		{
			for(j=(p-1)->T==p->T?j:maxv;f[j]>p->M;j--);
			p->ans=j;
		}
	}
}
bool cmp(quiry a, quiry b){return a.num<b.num;}
int main()
{
	init();
	work();
	sort(q+1,q+m+1,cmp);
	for(ll i=1;i<=m;i++)printf("%lld\n",q[i].ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值