题面:https://atcoder.jp/contests/abc145/tasks/abc145_e
题面估计都懂了,类似于背包问题。
首先,如果题目中没有给出 时间停止可以继续吃 这个条件的话,这个题就是一个裸的01背包问题。
然而,题目中加了这个条件,所以需要把背包问题转换一下:
之前背包的上限容量 是T,但是因为题目限制,所以可以把背包容量扩充到 T+w[i]-1
这个时候这个物品就可以超出 容量T ,并且小于 T+w[i] 也保证了不可能出现大于容量T还进行的情况。
所以状态转移方程:
应该都可以看懂
但是有一个坑点就是,wa了我好久,我们这样进行状态转移方程的时候,如果有重量大的先进行dp之后,就没办法继承前面重量小的状态,因为状态转移方程中:dp[x][y]与dp[x-1][y-w[i]]状态有关,所以要保证 y-w[i]这个状态存在并且是最优。所以我们应该按w从小到大排一下序,最后一遍O(n)即可。
AC:
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#include<stdio.h>
#include <string.h>
#include<algorithm>
#include <queue>
typedef long long ll;
const int mod=998244353;
const int maxn=1e6+5;
const ll INF=100000000000000005;
const double eps=1e-11;
using namespace std;
ll n,m,p;
struct node{
int w,v;
bool friend operator<(node a,node b)
{
return a.w<b.w;
}
}save[3005];
ll dp[3005][6005];
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld%lld",&save[i].w,&save[i].v);
sort(save+1,save+1+n);
for(int i=1;i<=n;i++)
{
for(int k=0;k<save[i].w+m;k++)
{
if(k>=save[i].w) dp[i][k]=max(dp[i-1][k],dp[i-1][k-save[i].w]+save[i].v);
else dp[i][k]=dp[i-1][k];
}
}
ll res=0;
for(int i=1;i<=n;i++) res=max(dp[n][m+save[i].w-1],res);
printf("%lld\n",res);
return 0;
}