给出
n
≤
1
e
5
n\leq1e5
n≤1e5个数,满足对于所有的
g
2
i
>
g
2
i
−
1
,
g
2
i
>
g
2
i
+
1
g_{2i}>g_{2i-1},g_{2i}>g_{2i+1}
g2i>g2i−1,g2i>g2i+1或者
g
2
i
<
g
2
i
−
1
,
g
2
i
<
g
2
i
+
1
g_{2i}<g_{2i-1},g_{2i}<g_{2i+1}
g2i<g2i−1,g2i<g2i+1。
对理解dp是一个不错的题,dp重在设计出来的状态是一个可以转化为子问题的状态,然后考虑对子状态的转移。
记录
f
i
,
0
∣
1
f_{i,0|1}
fi,0∣1分别表示到
i
i
i这个位置,波峰|波谷的最大保留值。
转移的时候考虑前一位,以波谷为例,若
a
i
<
a
i
−
1
a_{i}<a_{i-1}
ai<ai−1,有
f
i
,
1
=
f
i
−
1
,
0
+
1
f_{i,1}=f_{i-1,0}+1
fi,1=fi−1,0+1。否则
f
i
,
0
=
f
i
−
1
,
0
f_{i,0}=f_{i-1,0}
fi,0=fi−1,0。
为什么只需要考虑前一位呢,其实就如这个转移式告诉我们,如果这个点大于前面一个点,那么它无法成为波谷,只能成为波峰,而作为波峰答案自然是不变的,而波峰我们确实是希望它越大越好。所以这一位是最好的,之后的转移就不用再去考虑前面的位置了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=1e5+7;
int a[N];
int f[N][2]; // 0 represents decrease / 1 represents increase
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
f[1][0]=f[1][1]=1;
for(int i=2;i<=n;i++) {
f[i][0]=f[i-1][0];
f[i][1]=f[i-1][1];
if(a[i]<a[i-1]) f[i][0]=max(f[i][0],f[i-1][1]+1);
if(a[i]>a[i-1]) f[i][1]=max(f[i][1],f[i-1][0]+1);
}
printf("%d\n",max(f[n][0],f[n][1]));
return 0;
}