题目:数组里面相邻的且值同为x的两个数可以合成x+1,问数组的最小长度
input
5
4 3 2 2 3
output
2
思路难点:
意识到最终合成的结果是分截合成的,只要算出任意一截(从i到j)的顺序合成结果(此过程O(n2)),就能知道最终结果。
状态定义:
dp[i]表示前i个数可以合成的最小长度。
状态转移:
选择位置j,之前算出的dp[j]即是前j位的最小值,再将j到i位顺序合成。
for(int i = 1;i<=n;i++){
for(int j = 1;j<i;j++){
int t = 从j位到i位顺序合成的长度
//计算t耗时O(n)
dp[i] = min(dp[i],t+dp[j]);
}
}
总复杂度O(n3)
可以如下优化:
可以顺序合成的值保存下来,定义t[i][j]为i到j顺序合成的最小长度,t[i][j]= t[i][j-1]合成第j位,在已知t[i][j-1]的情况下计算t[i][j]的复杂度为O(1)。在此基础上进一步可以做如下优化。
for (int i = 1; i <= n; i++) {
int t = 0;
for (int j = i; j <= n; j++) {
que[++t] = a[j];
while (t != 0) {
if (que[t] == que[t - 1]) {
t--;
que[t]++;
}
else break;
}
dp[j] = min(dp[j], dp[i - 1] + t);
}
}
复杂度O(n2)
ac代码:
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <iomanip>
#include <string>
#include <algorithm>
#include <stack>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define ull unsigned long long
#define uint unsigned int
#define l(x) ((x)<<1)
#define r(x) ((x)<<1|1)
#define lowbit(x) ((x)&(-(x)))
#define ms(a,b) memset(a,b,sizeof(a))
#define NSYNC std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
using namespace std;
int a[550], sta[550], dp[550],n;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
dp[i] = i;
scanf("%d", &a[i]);
}
for (int i = 1; i <= n; i++) {
int t = 0;
for (int j = i; j <= n; j++) {
sta[++t] = a[j];
while (t != 0) {
if (sta[t] == sta[t - 1]) {
t--;
sta[t]++;
}
else break;
}
dp[j] = min(dp[j], dp[i - 1] + t);
}
}
printf("%d\n", dp[n]);
return 0;
}