CF1195C Basketball Exercise (dp + 贪心)
题解出处:https://www.luogu.org/problemnew/solution/CF1195C
很水的一道C题……目测难度在黄~绿左右。请各位切题者合理评分。
注意到可以选择的球员编号是严格递增的,因此可以把状态的第一维定义为球员编号,第二维描述编号同为 ii 的两名球员的选取情况。
定义状态:f[i][0/1/2]f[i][0/1/2] 表示选取了编号在 ii 及以前的球员,所能得到的身高总和最大值。其中,第二维的 00 表示编号为 ii 的球员一个都不选;11 表示只选上面一个;ii 表示只选下面一个。(显然没有上下都选的情况)
状态转移方程:
f[i][0]=max{f[i−1][0],f[i−1][1],f[i−1][2]}f[i][1]=max\lbrace f[i-1][0],f[i-1][2]\rbrace+height[i][1]f[i][1]=max{f[i−1][0],f[i−1][2]}+height[i][1]f[i][2]=max\lbrace f[i-1][0],f[i-1][1]\rbrace+height[i][2]f[i][2]=max{f[i−1][0],f[i−1][1]}+height[i][2]
Update: 用贪心可以证明,在最优解中,不会出现连续两列一个不取的情况。因此, f[i][0]f[i][0] 其实没有必要考虑来自 f[i-1][0]f[i−1][0] 的状态转移。
代码如下:
#include <bits/stdc++.h> using namespace std; typedef long long ll; int N; ll h[100005][3]; ll f[100005][3]; int main() { cin >> N; for (register int i = 1; i <= N; ++i) cin >> h[i][1]; for (register int i = 1; i <= N; ++i) cin >> h[i][2]; f[1][0] = 0; f[1][1] = h[1][1]; f[1][2] = h[1][2]; for (register int i = 2; i <= N; ++i) { f[i][0] = max(f[i - 1][0], max(f[i - 1][1], f[i - 1][2])); f[i][1] = max(f[i - 1][0], f[i - 1][2]) + h[i][1]; f[i][2] = max(f[i - 1][0], f[i - 1][1]) + h[i][2]; } cout << max(f[N][0], max(f[N][1], f[N][2])); return 0; }