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;
}