Luogu P5662 [CSP-J2019] 纪念品 题解 [ 绿 ] [ 背包 DP ]
纪念品:差点没做出噗叽组小朋友的题,如何呢???
感觉还是有点转化难度的背包题。
直接设暴力状态转移肯定是会超时的,不妨先考虑只有一个物品的特殊情况。然后就能发现当一个物品买了之后,第二天先试着卖出一定是最优的。因为卖出之后买入的价格是一样的,如果要继续持有该物品则等效于连续多天买该物品再在第二天卖出。于是我们把买卖区间化为了单个物品考虑,每一天的决策相互独立,后效性也就减小了,思想类似于反悔贪心。
因此就可以构建背包模型了,因为每天的物品是要在第二天才能盈利,所以 \(dp_{i,j}\) 表示第 \(i\) 天用了 \(j\) 元买东西,第 \(i+1\) 天所得的最大利润,跑完全背包转移即可。第 \(i+1\) 天能用于买东西的钱数即为 \(\max_{i=0}^{pre} pre-i+dp_i\)。因为每一天的决策相互独立,所以每天尽可能将下一天的初始钱数最大化一定是最优的。
时间复杂度 \(O(tnV)\)。
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
const int N=105,M=10005;
int t,n,m,p[N][N],dp[M];
int main()
{
//freopen("sample.in","r",stdin);
//freopen("sample.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>t>>n>>m;
for(int i=1;i<=t;i++)
for(int j=1;j<=n;j++)
cin>>p[i][j];
for(int i=1;i<t;i++)
{
memset(dp,-0x3f,sizeof(dp));
dp[0]=0;
for(int j=1;j<=n;j++)
for(int k=p[i][j];k<=m;k++)
dp[k]=max(dp[k],dp[k-p[i][j]]+p[i+1][j]);
int nxt=0;
for(int j=0;j<=m;j++)
nxt=max(nxt,dp[j]+m-j);
m=nxt;
}
cout<<m;
return 0;
}

浙公网安备 33010602011771号