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;
}
posted @ 2025-06-09 22:27  KS_Fszha  阅读(23)  评论(0)    收藏  举报