我们根据题意,发现这是一个 DP 题,定义 fi,j 表示在高度为 i,当前要爬的树为 j 所能获得的最大柿子数。
易得状态转移方程:fi,j=max(fi−1,j,fi−delta,k)(1≤k≤n),当 i>delta 时后一项成立。
于是我们得到了一个时间复杂度为 O(H×N2),空间复杂度为 O(N×H) 的算法啦。。
然而 N,H=2000 的数据这个时间复杂度还是难以承受,所以需要进一步的优化。
我们发现对于每个 i,第二个转移的 i−delta 总是固定的,所以就可以直接处理出高度为 i 时 fi,j 的最大值,时间复杂度降到 O(N×H)
接下来上代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| #include <cstdio> #include <iostream> using namespace std; #define gc ch = getchar() inline int read() { int x = 0,f = 1; char gc; for (; ch < '0' || ch > '9'; gc) if (ch == '-') f = -1; for (; ch >= '0' && ch <= '9'; gc) x = x * 10 + ch - '0'; return x * f; } #undef gc
int n, h, d, g[2005], a[2005][2005], f[2005][2005];
int main() { n = read(); h = read(); d = read(); for (int i = 1; i <= n; i++) { a[i][0] = read(); for(int j = 1; j <= a[i][0]; j++) a[i][read()]++; } for (int i = 1; i <= h; i++) { for (int j = 1; j <= n; j++) f[i][j] = f[i - 1][j] + a[j][i]; if (i > d) for (int j = 1; j <= n; j++) f[i][j] = max(f[i][j], g[i - d] + a[j][i]); for (int j = 1; j <= n; j++) g[i] = max(f[i][j], g[i]); } printf("%d", g[h]); }
|