【YBTOJ】划分数列

题目链接:

链接

题目大意:

给定一个长度为 \(n\) 的数列 \(A\),要求划分最少的段数,使得每一段要么单调不降,要么单调不升。

正文:

考虑用动态规划,设 \(f_i\) 表示从一到 \(i\) 最少可以划分的段数。

则有转移方程:

\[f_i=\min(f_{u_i-1},f_{d_i-1})+1 \]

其中 \(u_i\) 表示以 \(i\) 结尾单调不降的一段的起点,\(d_i\) 则表示以 \(i\) 结尾单调不升的一段的起点。

这个数列 \(u,d\) 可以用 \(O(n)\) 的时间复杂度预处理出来,那么总时间复杂度为 \(O(n+n)=O(n)\)

代码:

int main()
{
	scanf ("%d", &n);
	for (int i = 1; i <= n; i++)
		scanf ("%d", &a[i]);
	u[1] = d[1] = 1;
	for (int i = 2; i <= n; i++)
	{
		if(a[i - 1] <= a[i]) u[i] = u[i - 1]; 
		else u[i] = i;
		if(a[i - 1] >= a[i]) d[i] = d[i - 1]; 
		else d[i] = i;
	}
	memset(f, 127 / 3, sizeof f);
	f[1] = f[0] = 0;
	for (int i = 1; i <= n; i++)
		f[i] = min(f[u[i] - 1] + 1, f[d[i] - 1] + 1);
	printf("%d", f[n]);
	return 0;
} 
posted @ 2020-12-09 18:07  Jayun  阅读(268)  评论(0编辑  收藏  举报