版权声明:https://blog.csdn.net/huashuimu2003 https://blog.csdn.net/huashuimu2003/article/details/89763633
title
【问题描述】
【输入】
【输出】
输出m行,每行一个整数,对于每个计划输出最大可能的价值和
【输入输出样例1】
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
【数据范围】
analysis
把购物时间排个序,然后做背包?
但是我们发现,预算和金额都非常大,没法背包怎么办呢?
经典的做法是,互换一下,将价值设为状态预算设为背包的值,然后再二分判断就好。
即设 表示前 个店能够购物,购买价值为 的物品。
状态转移方程就很好想了:
if (j>=a[i].v) f[i][j]=min(f[i-1][j],f[i-1][j-a[i].v]+a[i].c);
else f[i][j]=f[i-1][j];
伪装成难题的水题~
这话可不是我说的,是这位大佬说的:BAJim_H,但是这道题还就是这么搞的。。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=300,maxv=300;
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
struct Orz{int c,v,t;}a[maxn+10];
inline bool cmp(Orz x,Orz y)
{
return x.t<y.t;
}
int t[maxn+10];
ll f[maxn+10][maxn*maxv+10];//f[i][j]表示前i个店能够购物,购买价值为j的物品
int main()
{
freopen("market.in","r",stdin);
freopen("market.out","w",stdout);
int n,m;read(n);read(m);
for (int i=1; i<=n; ++i) read(a[i].c),read(a[i].v),read(a[i].t),t[i]=a[i].t;
sort(t+1,t+n+1);
sort(a+1,a+n+1,cmp);
for (int i=1; i<=maxn*maxv; ++i) f[0][i]=99999999999999999ll;
for (int i=1; i<=n; ++i)
for (int j=1; j<=maxn*maxv; ++j)
if (j>=a[i].v) f[i][j]=min(f[i-1][j],f[i-1][j-a[i].v]+a[i].c);
else f[i][j]=f[i-1][j];
for (int i=1; i<=n; ++i)
for (int j=maxn*maxv-1; j>=0; --j)
f[i][j]=min(f[i][j],f[i][j+1]);
while (m--)
{
int T,M;
read(T);read(M);
int s=upper_bound(t+1,t+n+1,T)-t-1;
ll ans=upper_bound(f[s],f[s]+n*maxv+1,M*1ll)-f[s]-1;
printf("%lld\n",ans);
}
return 0;
}