题目链接:
题目大意:
给定一个长度为 (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;
}