技巧1:f[i][j]占用空间过大,可以考虑f[j][i]能否优化掉一维
CF 1582 E. Pchelyonok and Segments
输入 t(t≤100) 表示 t 组数据。每组数据输入 n(1≤n≤1e5) 和长为 n 的整数数组 a (1≤a[i]≤1e9),所有数据的 n 之和不超过 1e5。从 a 中选尽可能多的互不相交的子数组,设有 k 个子数组,需满足:
1. 从左到右第一个子数组的长度恰好是 k,第二个的长度恰好是 k-1,……,最后一个的长度恰好是 1;
2. 从左到右第 i 个子数组的元素和严格小于第 i+1 个子数组的元素和。输出 k 的最大值。注:子数组是连续的。
| 输入 5 1 1 3 1 2 3 5 1 1 2 2 3 7 1 2 1 1 3 2 6 5 9 6 7 9 7 输出 1 1 2 3 1 |
|---|
思路:f[i][j]表示从i开始的后缀,最大长度为j的最小值。
然后会发现这种写法需要占用的空间太大,会MLE
考虑f[j][i]然后优化掉j这一维
static final int N = 100010;static int[] a = new int[N];static long[] s = new long[N];static long[] f = new long[N], g = new long[N];static int n;static void solve() {int T = ni();while (T-- > 0) {n = ni();s[n + 1] = 0;for (int i = 1; i <= n; i++)a[i] = ni();Arrays.fill(f, 0);Arrays.fill(g, 0);for (int i = n; i >= 1; i--) {s[i] = s[i + 1] + a[i];f[i] = Math.max(f[i + 1], a[i]);}int c = 1;for (int k = 2; ; k++) {g[n] = 0;for (int i = n; i >= 1; i--) {g[i] = g[i + 1];if (i + k <= n && s[i] - s[i + k] < f[i + k])g[i] = Math.max(g[i], s[i] - s[i + k]);}long[] t = g;g = f;f = t;if (f[1] == 0) break;c++;}out.println(c);}}
