T1:倍数序列3

本题难度中等,思路和 LIS 类似,用 dp[i] 表示以 \(a_i\) 结尾的倍数序列的个数。如果 \(a_i\)\(a_j\) 的倍数,倍数序列个数就是 \(dp[j]\),枚举所有 \(j\) 求和即可得到 \(dp[i]\) 。时间复杂度:\(O(n^2)\)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

int main() {
    int n;
    cin >> n;
    
    vector<ll> a(n);
    rep(i, n) cin >> a[i];
    
    sort(a.begin(), a.end());
    
    ll ans = 0;
    vector<ll> dp(n);
    rep(i, n) {
        dp[i] = 1;
        rep(j, i) if (a[i]%a[j] == 0) {
            dp[i] += dp[j];
        }
        ans += dp[i];
    }
    
    cout << ans << '\n';
    
    return 0;
}

T2:火箭载荷

本题难度中等,可以化为01背包模板。将升空条件写出,做变形之后,通过选取适当的量作为物品的大小和价值,就可以化为01背包模板。
dp[v] 表示载荷使用 \(v\) 体积后的最大重量

转移方程:
\( dp[j] = \max\{dp[j-v_i] + w_i\} \)

还需满足条件 \(W+dp[j] + (V-j) \cdot c \leqslant (V-j) \cdot k\)

但这里以体积作为代价去求最大重量,会把本来合法的较小一些的方案给忽略掉,将对答案有致命的影响

重量固定时,体积尽可能小
dp[j] 表示载荷重量恰好为 \(j\) 时,对应的最小体积

转移方程:

\( dp[j] = \min\{dp[j-w_i] + v_i\} \)

由于这个状态没有转移就是无解的,为了使得它有解,应该尽可能的去转移
设置 \(dp\) 的初值为无穷大
\(dp[0] = 0\)

还需满足条件:\(W+j+(V-dp[j]) \cdot c \leqslant (c-dp[j]) \cdot k\)

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

inline void chmin(int& x, int y) { if (x > y) x = y; }

int main() {
    int n, W, V, c, k;
    cin >> n >> W >> V >> c >> k;
    
    const int MX = 100001;
    const int INF = 1001001001;
    vector<int> dp(MX, INF);
    dp[0] = 0;
    rep(i, n) {
        int w, v;
        cin >> w >> v;
        for (int j = MX-1; j >= w; --j) {
            chmin(dp[j], dp[j-w]+v);
        }
    }
    
    int ans = -1;
    rep(i, MX) {
        if (dp[i] <= V and (V-dp[i])*k >= W+i+(V-dp[i])*c) {
            ans = i;
        }
    }
    
    cout << ans << '\n';
    
    return 0;
}