[CSP-J2019] 纪念品

[CSP-J2019] 纪念品

知识点:完全背包

注意到,对于某件商品,我们可以当天卖出当天买回,于是我们在一天中对于某件商品,可以有以下的策略:

1、不买

2、买完后第二天卖掉

3、买完后过几天卖掉

对于策略3,我们可以将其转化为:当天买;然后第二天卖掉,第二天买回;然后第三天卖掉,第三天买回......

所以对于每件物品,我们可以只计算过一天的收益,如果一件物品需要经过多天才有收益,我们可以将其拆解为这些天的收益和。将总收益转化为每天的收益和即可。

于是我们拆成解决每天的收益即可。

我们尝试使用动态规划解决,定义 \(dp[j][k]\) 表示对于某一天,前 \(j\) 个物品,本金为 \(k\) 的时候的最大收益。于是我们的转移是这样的。

\[dp[j][k] = max_{k - v * p[i][j] \ge 0}(dp[j - 1][k - p[i][j] * v] + v * (p[i + 1][j] - p[i][j])) \]

其中 \(p[i][j]\) 表示第 \(i\) 天第 \(j\) 件商品的价格。

很显然,这是一个完全背包的转移,于是我们化简,回顾一下化简的过程

\[dp[j][k - p[i][j]] = max_{k - v * p[i][j] \ge 0}(dp[j - 1][k - p[i][j] * v] + (v - 1) * (p[i + 1][j] - p[i][j])) \]

结合以上两个式子,得出

\[dp[j][k] = max(dp[j - 1][k], dp[j][k - p[i][j]] + p[i + 1][j] - p[i][j]) \]

复杂度 $O(T \cdot N \cdot M) $

#include <bits/stdc++.h>
#define endl '\n'
#define ls u << 1
#define rs u << 1 | 1
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f, N = 5e5 + 10;
const int MOD = 1e9 + 7;
const double eps = 1e-6;
const double PI = acos(-1);
inline int lowbit(int x) {return x & (-x);}

inline void solve() {
    int s, d, m; cin >> d >> s >> m;
    vector<vector<int>> p(d + 1, vector<int>(s + 1));
    for (int i = 1; i <= d; i ++ ) {
        for (int j = 1; j <= s; j ++ ) {
            cin >> p[i][j];
        }
    }
    int ans = m;
    for (int i = 1; i < d; i ++ ) {
        vector<vector<int>> dp(2, vector<int>(N));
        int mx = 0;
        for (int j = 1; j <= s; j ++ ) {
            int v = j & 1;
            for (int x = 0; x <= ans; x ++ ) {
                dp[v][x] = dp[v ^ 1][x];
                if (x - p[i][j] >= 0)
                    dp[v][x] = max(dp[v][x], dp[v][x - p[i][j]] + p[i + 1][j] - p[i][j]);
                mx = max(mx, dp[v][x]);
            }
        }
        ans += mx;
    }
    cout << ans << endl;
}
signed main() {
#ifdef DEBUG
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    auto now = clock();
#endif
    ios::sync_with_stdio(false), cin.tie(nullptr);
    cout << fixed << setprecision(2);
    int _ = 1;
//    cin >> _;
    while (_ -- )
        solve();
#ifdef DEBUG
    cout << "============================" << endl;
    cout << "Program run for " << (clock() - now) / (double)CLOCKS_PER_SEC * 1000 << " ms." << endl;
#endif
    return 0;
}
posted @ 2024-04-10 15:00  Time_Limit_Exceeded  阅读(26)  评论(0编辑  收藏  举报