题目背景
NOIP2013 提高组 D2T2
题目描述
花匠栋栋种了一排花,每株花都有自己的高度。花儿越长越大,也越来越挤。栋栋决定把这排中的一部分花移走,将剩下的留在原地,使得剩下的花能有空间长大,同时,栋栋希望剩下的花排列得比较别致。
具体而言,栋栋的花的高度可以看成一列整数 h1,h2,…,hnh1,h2,…,hn。设当一部分花被移走后,剩下的花的高度依次为 g1,g2,…,gmg1,g2,…,gm,则栋栋希望下面两个条件中至少有一个满足:
条件 A:对于所有的 1≤i≤m21≤i≤2m,有 g2i>g2i−1,同时对于所有的 1≤i≤m21≤i≤2m,有 g2i>g2i+1;
条件 B:对于所有的 1≤i≤m21≤i≤2m,有 g2i<g2i−1,同时对于所有的 1≤i≤m21≤i≤2m,有 g2i<g2i+1。
注意上面两个条件在 m=1m=1 时同时满足,当 m>1 时最多有一个能满足。
请问,栋栋最多能将多少株花留在原地。
输入格式
第一行包含一个整数 n,表示开始时花的株数。
第二行包含 n 个整数,依次为 h1,h2,…,hn,表示每株花的高度。
输出格式
输出一行,包含一个整数,表示最多能留在原地的花的株数。
输入输出样例
输入 #1
5 5 3 2 1 2
输出 #1
3
第一种解法——巧妙的DP大法
通过观察题面可以发现递推关系
于是可以用两个数组分别记录到i下降和到i上升
容易得出递推公式:
if(a[i]>a[i-1])f[i][0]=f[i-1][1]+1;
else f[i][0]=f[i-1][0];
if(a[i]<a[i-1])f[i][1]=f[i-1][0]+1;
else f[i][1]=f[i-1][1];
代码君奉上
#include<bits/stdc++.h>
using namespace std;
#define N 100010
int a[N],f[N][2]={0};
int n,tmp=0;
int main(){
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++){
if(a[i]>a[i-1])f[i][0]=f[i-1][1]+1;
else f[i][0]=f[i-1][0];
if(a[i]<a[i-1])f[i][1]=f[i-1][0]+1;
else f[i][1]=f[i-1][1];
}
cout<<max(f[n][0],f[n][1]);
return 0;
}
第二种解法——更巧妙的贪心(Orz)
假设有N朵花
大致根据我们学过的函数思想,我们可以知道,存在m个g(2i)点在波峰或波谷上。
因为在波峰到波谷或者从波谷到波峰上的点单调,所以不满足这个性质,我们决定舍去这些点。
那么对于什么样的点留下呢,我们可以取那些波峰和波谷。
我们可以打标记,用flag表示。再定义一个计数的ans。
我们首先肯定要取1点,并且1点肯定是一个波峰或波谷(这个很重要)
所以我们先判断一下hi[1]和hi[2]的关系(hi [ ]表示高度)
如果hi[1]<hi[2] 说明1是波谷,那么我们标记flag=-1
如果hi[1]>hi[2] 说明1是波峰,那么我们标记flag=1
所以我们只需要判断是否hi[i]乘以flag > h[i+1]乘以flag
如果是的话 ,那么ans++;
否则说明状态改变了,那么就让标记flag*=-1
通过一个for循环,我们就求出了ans的值
所以我们只需输出:(N-ans)
好,下面我们来看代码(时间复杂度O(N))
#include <iostream>
using namespace std;
int main()
{
int N;
int hi[1000001]={0};
int ans=0;
cin>>N;
for(int i=1;i<=N;i++)
{
cin>>hi[i];
}
int flag;
if(hi[1]>hi[2]) flag=1;
else flag=-1;
for(int i=2;i<=N-1;i++)
{
if(hi[i]*flag>=hi[i+1]*flag) ans++;
else flag*=-1; }
cout<<N-ans;
}
在百忙之中写一篇题解也比较辛苦,别忘了点个赞!