求最长不下降/上升/下降/不上升子序列

求最长不下降/上升/下降/不上升子序列

说在前面的话

求最长不下降/上升/下降/不上升/子序列的原理都是一样的,只是有无等于号或者大于小于号的关系,懂了一个其余的就懂了,所以我这里只拿不下降子序列来举例子吧。

\(n^2\)的做法

原理

求最长不下降子序列的话,\(i\)位置应该和\(i\)位置之前的位置里面小于等于\(i\)位置上的值且最长不下降子序列最长的那个,所以可以枚举\(i\)位置之前的每一个点,然后按照上面说的选取就好了。

代码

题面详见

#include<iostream>
#include<cstdio>

using namespace std;
const int Max = 201;
int n;
int a[Max],f[Max],c[Max];
int Ans[Max];

int main()
{
	scanf("%d",&n); 
	for(int i = 1;i <= n;++ i) 
		scanf("%d",&a[i]),f[i] = 1;//输入数据将以每一个数结尾的最长不下降子序列标记为1 
	for(int i = 1;i <= n;++ i)
		for(int j = 1;j < i;++ j)
			if(a[i] >= a[j])//满足最长不下降 , 也就是大于等于 
				if(f[i] < f[j] + 1)
					f[i] = f[j] + 1,c[i] = j;//记录 
	int ans = 0,qwq = 1;
	for(int i = 1;i <= n;++ i)
		if(f[i] > ans)//找最大的 
			ans = f[i],qwq = i;//记录最大的所在的下标 
	printf("max=%d\n",ans);
	int aaa = ans;
	while(aaa --)//到这找回去 
	{
		Ans[aaa + 1] = a[qwq];//用数组储存 
		qwq = c[qwq];
	}
	for(int i = 1;i <= ans;++ i)//正着输出 
		cout<<Ans[i]<<" ";
	return 0;
}

nlogn的做法

这才是这篇文章的重点!!!

原理

开一个数组(注意是额外开一个数组,不是存储读入数字串的数组),第一个数理所当然的放在这个数组的第一个位置上面,如果进来的下一个数是符合不下降条件的,那么久放在他的后面,不然就在这个序列里面找到第一个比他大的数替换掉。

为什么要这样呢?
看完上面应该是有一种疑惑,这样替换的话会不会影响后面的呢?答案当然是否定的。
来说一下理由:
如果当前数组中放了1,3,5这三个数,下一个数是2,如果放在了第一个比他大的数的位置上,那就会放在3上面,这个时候数组中存储的数据就成了1,2,5,然后当下一个数进来的时候是和5比较是不是符合不下降的条件,所以把2替换在3的位置上面并没有影响。
具体说一下:就是如果这个数替换的那个数之后还有数,必然不会影响之后一个数拿过来之后的第一项操作,也就是先比较一下放在最后面是不是会符合不下降,那如果后面没有数了,他就是最后一个的话,用这个小的替换了前面的大的,也必然会使结果更优,所以没有问题。

代码

//最长不下降子序列nlogn  Song 

#include<cstdio>
#include<algorithm>
using namespace std;

int a[40005];
int d[40005];

int main()
{
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    if (n==0)  //0个元素特判一下 
    {
        printf("0\n");
        return 0;
    }
    d[1]=a[1];  //初始化 
    int len=1;
    for (int i=2;i<=n;i++)
    {
        if (a[i]>=d[len]) d[++len]=a[i];  //如果可以接在len后面就接上,如果是最长上升子序列,这里变成> 
        else  //否则就找一个最该替换的替换掉 
        {
            int j=upper_bound(d+1,d+len+1,a[i])-d;  //找到第一个大于它的d的下标,如果是最长上升子序列,这里变成lower_bound 
            d[j]=a[i]; 
        }
    }
    printf("%d\n",len);    
    return 0;
}
posted @ 2019-11-11 20:10  acioi  阅读(925)  评论(2编辑  收藏  举报