cf 1312E dp中等题

题目:数组里面相邻的且值同为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;
}
发布了86 篇原创文章 · 获赞 8 · 访问量 2215

猜你喜欢

转载自blog.csdn.net/Fawkess/article/details/104785068
今日推荐