CF1312E Array Shrinking

Array Shrinking

Description

给定一个数组,若数组中相邻的两个数相同(设都为 aa),则它们合并为一个数,其值为 a+1a + 1。求合并后数组的最小长度。

Solution

  • 考虑区间 DPDP, 设 dp[l][r]dp[l][r] 表示区间 [l,r][l,r] 合并后的最小长度,并设 w[l][r]w[l][r] 表示区间 [l,r][l,r] 合并后的和
  • 状态转移方程:dp[l][r]=min(dp[l][r],dp[l][mid]+dp[mid+1][r])dp[l][r] = \min(dp[l][r], dp[l][mid] + dp[mid + 1][r])
  • dp[l][mid]=dp[mid+1][r]=1dp[l][mid] = dp[mid + 1][r] = 1,并且 w[l][mid]=w[mid+1][r]w[l][mid] = w[mid + 1][r],则 dp[l][r]=1w[l][r]=w[l][mid]+1dp[l][r] = 1,w[l][r] = w[l][mid] + 1

Code

Array Shrinking
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
30
31
32
33
34
35
36
#include<bits/stdc++.h>
#define boost std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)

using namespace std;
using LL = long long;

constexpr int MAXN = 505;
constexpr LL M = 998244353;

int n, a[MAXN], dp[MAXN][MAXN], w[MAXN][MAXN];

template <typename T> inline void read(T &x) {
int f = 1; x = 0;
char ch = getchar();
while (!isdigit(ch)) f = (ch == '-') ? -1 : 1, ch = getchar();
while (isdigit(ch)) x = x * 10 + ch - 48, ch = getchar();
x *= f;
}

int main() {
boost;
cin >> n;
memset(dp, 0x3f, sizeof(dp));
for (int i = 1; i <= n; i++) cin >> a[i], dp[i][i] = 1, w[i][i] = a[i];
for (int len = 2; len <= n; len++)
for (int l = 1; l + len - 1 <= n; l++) {
int r = l + len - 1;
for (int mid = l; mid < r; mid++) {
dp[l][r] = min(dp[l][r], dp[l][mid] + dp[mid + 1][r]);
if (dp[l][mid] == 1 && dp[mid + 1][r] == 1 && w[l][mid] == w[mid + 1][r])
dp[l][r] = 1, w[l][r] = w[l][mid] + 1;
}
}
cout << dp[1][n] << endl;
return 0;
}