链接

题目大意:给定n个饭盒,和q次询问,每个饭盒拥有美味值v,代价w,取走时间e。每次询问包含一个时间t,和代价上限k。问再此时间,此代价下,能获得的最大美味值是多少?

背包问题,dp[i][j]表示当前可以取走i件物品,且代价为小于等于j可获得的最大值。那么在这问题里,最直接的方法就是选出符合条件的饭盒进行背包DP,但是这会超时。

其实我们只需要把饭盒按照取走时间降序排序,然后做一遍背包DP,这样dp数组的物品维度使按照取走顺序排列的。(dp[1]代表对最后被拿走的物品进行DP,dp[2]代表最后一个和倒数第二个被取走的物品进行DP,以此类推)然后用二分法确定DP[i][j]中的i(某时间段哪些饭盒可以进行DP)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;


int dp[10001][10001];
struct hehe{

int v,w;
long long e;
}a[10001];


bool cmp(hehe l,hehe r){
return l.e>r.e;
}
int n,q;

int find(long long num){
int l=1;
int r=n;
int mid;
int ans=0;
while(l<=r){
mid=(l+r)/2;
if(a[mid].e>num){
ans=mid;
l=mid+1;
}
else{
r=mid-1;
}
}
return ans;
}

int main(){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d%d%lld",&a[i].v,&a[i].w,&a[i].e);
}
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++){
for(int j=0;j<=10000;j++){
dp[i][j]=dp[i-1][j];
if(j>=a[i].w){
dp[i][j]=max(dp[i][j],dp[i-1][j-a[i].w]+a[i].v);
}
}
}
int t,k;
for(int i=1;i<=q;i++){
scanf("%lld%d",&t,&k);
cout<<dp[find(t)][k]<<endl;
}

}