Educational Codeforces Round 83 (Rated for Div. 2) E - Array Shrinking ( 区间DP O(n^3) || 栈+DP O(n^2) )
挂机一个多小时都没想出来这道题,不过好在前四题切的快还是上分了
看到有人说这题是区间DP裸题...我怀疑我要回炉再造了
两种解法,一种是O(n^3)的区间DP
先预处理哪些段可以合并成为一个数字,复杂度n^3,再区间DP
f(i, j) = min(f(i, k) + f(k + 1, j)) ( i <= k < j)
#include <cstdio> #include <algorithm> using namespace std; const int N = 510; int a[N], num[N][N], f[N][N]; int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); num[i][i] = a[i]; } for (int len = 1; len < n; len++) for (int l = 1; l <= n - len; l++) { int r = l + len; f[l][l] = 1; for (int i = l; i < r; i++) if (num[l][i] == num[i + 1][r] && num[l][i] > 0) num[l][r] = num[l][i] + 1; if (num[l][r] > 0) f[l][r] = 1; else f[l][r] = r - l + 1; } f[n][n] = 1; for (int len = 1; len < n; len++) for (int l = 1; l <= n - len; l++) { int r = l + len; for (int i = l; i < r; i++) f[l][r] = min(f[l][r], f[l][i] + f[i + 1][r]); } printf("%d", f[1][n]); return 0; }
但是其实有更美观复杂度更低的做法(学长教我的
用栈把预处理优化到n^2,然后用d[i]表示前i个最少能变成几个,递推式就变成了
d[i] = d[j - 1] + 1 (if i ~ j可以合并成一个)
#include <cstdio>
#include <algorithm>
#include <stack>
using namespace std;
const int N = 510;
int a[N], d[N];
int main() {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i <= n; i++) {
stack < int > s;
d[i] = d[i - 1] + 1;
s.push(a[i]);
for (int j = i - 1; j > 0; j--) {
if (s.empty() || s.top() != a[j])
s.push(a[j]);
else {
int u = a[j];
while (!s.empty()) {
if (u != s.top())
break;
u = s.top() + 1;
s.pop();
}
if (s.empty())
d[i] = min(d[i], d[j - 1] + 1);
s.push(u);
}
}
}
printf("%d", d[n]);
return 0;
}

浙公网安备 33010602011771号