【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;
}