划分数列
ybtoj DP-2-1
题目大意
给你一个数列,让你划分出最少的段数,使每段要么单调不降,要么单调不增
输入样例#1
6
1 2 3 2 2 1
输出样例#1
2
输入样例#2
9
1 2 1 2 1 2 1 2 1
输出样例#2
5
输入样例#3
7
1 2 3 2 1 999999999 1000000000
输出样例#3
3
数据范围
1⩽n⩽100000,ai1\leqslant n \leqslant 100000, a_i1⩽n⩽100000,ai在 intintint范围内。
解题思路
设fi,1,fi,2f_{i,1},f_{i,2}fi,1,fi,2为前i个数划分,且最后一段为下降/上升的最小划分段数
如果ai⩾ai−1a_i\geqslant a_{i-1}ai⩾ai−1那么fi,2=fi−1,2f_{i,2}=f_{i-1,2}fi,2=fi−1,2
如果ai⩽ai−1a_i\leqslant a_{i-1}ai⩽ai−1那么fi,1=fi−1,1f_{i,1}=f_{i-1,1}fi,1=fi−1,1
就是加进最后一段
如果重开一段,那就+1
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 100010
using namespace std;
int n, a[N], f[N][3];
int main()
{memset(f, 127/3, sizeof(f)); scanf("%d", &n);scanf("%d", &a[1]);f[1][1] = f[1][2] = 1;for (int i = 2; i <= n; ++i){scanf("%d", &a[i]);if (a[i] >= a[i - 1]) f[i][2] = f[i - 1][2];//直接加进去if (a[i] <= a[i - 1]) f[i][1] = f[i - 1][1];f[i][1] = min(f[i][1], min(f[i - 1][1], f[i - 1][2]) + 1);//新开一段f[i][2] = min(f[i][2], min(f[i - 1][1], f[i - 1][2]) + 1);}printf("%d", min(f[n][1], f[n][2]));//求最大值return 0;
}