题目地址

https://www.luogu.org/problemnew/show/P1970

思路

看到这个题,很容易联想到最长上升子序列,但是要想找出其中的联系,又似乎没有那么容易,其实我们模拟一下就可以知道大概地思路了

例如上面这个样例,按照题意,必须按照一上一下排列,那么就有先上和现下两种情况,我们不妨分开讨论(其实思路是一样的)。

    我们以先找向下的数为例, 我们先将5放入一个数组f,表示5要保留,然后我们要找一个更小的数,恰好3比5小,所以将3也放入数组,继续

我们就要找一个更大的数,恰好4比3大,放入,然后更小得数,2放入,然后更大,4放入(好巧..),然后我们要找更小的数,但是

6比4大,然后我们考虑,以一个更大的数为标准找跟小的数,可以找到的更多数,所以我们用6更新掉4,也就是将4移走(这就是与最

长上升子序列相似的地方)。当然,如果找到的数与当前的数一样,那么久按照第二种方法处理。

   然后我们按照同样的方法找一遍现找向上的数,取两个长度中的大的一个。最后就是答案了(似乎比最长上升子序列更简单......)、

  具体代码实现的话,我的思路是可以找一个变量记录方向,然后每次找到新点之后,将方向改变(所谓方向,其实就是下一个点要更大还是更小),用一个数组f

来存放进去的数(既留下的数),并用一个变量len来记录它的长度,最后输出长度就好了。

代码

 #include<cstdio>
#include<iostream>
using namespace std;
int n,a[],f[];
bool fx=;//0时找更小的,1时找更大的
int main()
{
scanf("%d",&n);
for(int i=;i<=n;++i)
{
scanf("%d",&a[i]);//用a来存花的高度
}
int len1=;//len用来记录留下花的个数
f[++len1]=a[];//先将第一个放入
fx=;//先寻找更小的
for(int i=;i<=n;++i)
{
if(fx==)
{
if(a[i]<f[len1])//符合要求就放入
{
f[++len1]=a[i];
fx=;//改变方向
}
else//不符合要求就更新当前点(不用改变方向)
f[len1]=a[i];
}
if(fx==)//同样方法判断向上找的情况
{
if(a[i]>f[len1])
{
f[++len1]=a[i];
fx=;
}
else
f[len1]=a[i];
}
}
memset(f,,sizeof(f));
int len2=;//与上方雷同,只不过实现找更大的
f[++len2]=a[];
fx=;
for(int i=;i<=n;++i)
{
if(fx==)
{
if(f[len2]>a[i])
{
f[++len2]=a[i];
fx=;
}
else
f[len2]=a[i];
}
if(fx==)
{
if(f[len2]<a[i])
{
f[++len2]=a[i];
fx=;
}
else
f[len2]=a[i];
}
}
printf("%d",max(len1,len2));//输出两种情况中更大的一种情况
return ;
}
05-08 15:08