花匠
【题目描述】
花匠栋栋种了一排花,每株花都有自己的高度。花儿越长越大,也越来越挤。栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致。
具体而言,栋栋的花的高度可以看成一列整数H1,H2,…,Hn。设当一部分花被移走后,剩下的花的高度依次为G1,G2,…,Gm,则栋栋希望下面两个条件中至少有一个满足:
条件A:对于所有的1< i <m/2,G2*i > G2*i-1,且G2*i > G2*i+1;
条件B:对于所有的1< i <m/2,G2*i < G2*i-1,且G2*i < G2*i+1。
注意上面两个条件在m = 1时同时满足,当m > 1时最多有一个能满足。
请问,栋栋最多能将多少株花留在原地。
【输入描述】
输入的第一行包含一个整数n,表示开始时花的株数。
第二行包含n个整数,依次为H1,H2,…,Hn,表示每株花的高度。
【输出描述】
输出一行,包含一个整数m,表示最多能留在原地的花的株数。
【样例输入】
5
5 3 2 1 2
【样例输出】
3
【数据范围及提示】
对于 20%的数据,n ≤ 10;
对于 30%的数据,n ≤ 25;
对于 70%的数据,n ≤ 1000,0 ≤ Hi ≤ 1000;
对于 100%的数据,1 ≤ n ≤ 100,000,0 ≤ Hi ≤ 1,000,000。
解法一:
抖动序列DP:O(n^2)
源代码: #include<cstdio> #include<algorithm> using namespace std; int n,i[100001],f[100001][2]={0}; //f[i][0]代表小大小,f[i][1]代表大小大。 int main() //自惭形秽的O(n^2)DP。 { scanf("%d",&n); for (int a=1;a<=n;a++) scanf("%d",&i[a]); f[1][1]=f[1][0]=1; //边界。 for (int a=2;a<=n;a++) { int t1(0),t2(0); //t1代表降序到达i[b]的最大值,t2代表升序到达i[b]的最小值。 for (int b=1;b<a;b++) //取最大值。 { if (f[b][0]>t1&&i[b]>i[a]) t1=f[b][0]; if (f[b][1]>t2&&i[b]<i[a]) t2=f[b][1]; } f[a][1]+=t1+1; //升序到达了i[a]。 f[a][0]+=t2+1; //降序到达了i[a]。 } printf("%d",max(f[n][0],f[n][1])); //输出最大值。 return 0; }
优化后:O(n)
源代码: #include<cstdio> #include<algorithm> using namespace std; int n,i[100001],f[100001][2]={0}; int main() //转换思想的O(n)DP。 { scanf("%d",&n); for (int a=1;a<=n;a++) scanf("%d",&i[a]); f[1][0]=f[1][1]=1; //边界。 for (int a=2;a<=n;a++) //依次传值,f[i][0]表示前i株花降序到达的最大值,f[i][1]为与此同类。 { if (i[a]<i[a-1]) //可降序到达。 { f[a][0]=max(f[a-1][1]+1,f[a-1][0]); //选不选此株花。 f[a][1]=f[a-1][1]; } if (i[a]==i[a-1]) //纯传值。 { f[a][0]=f[a-1][0]; f[a][1]=f[a-1][1]; } if (i[a]>i[a-1]) //可升序到达。 { f[a][1]=max(f[a-1][0]+1,f[a-1][1]); f[a][0]=f[a-1][0]; } } printf("%d",max(f[n][0],f[n][1])); //输出最大值。 return 0; }
解法二:
模拟解决:
源代码: #include<cstdio> int n,ans=2,i[100001]; //ans一开始便包括了始点和终点。 bool s; int main() { scanf("%d",&n); for (int a=1;a<=n;a++) scanf("%d",&i[a]); s=i[1]>i[2]; //模拟的思想为:可以将题意转化为求转折点的最多个数,再通过判断升降序列即可求解。 for (int a=3;a<=n;a++) { if (s&&i[a]>i[a-1]) //降序转折。 { ans++; s=0; } if (!s&&i[a]<i[a-1]) //升序转折。 { ans++; s=1; } } printf("%d",ans); return 0; }