nlogn求最长不上升子序列

这种问题一般都比较熟悉,我们先看n^2的算法

导弹拦截

时间限制: 1 Sec  内存限制: 128 MB
提交: 106  解决: 61
[提交][状态][讨论版]

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意 的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所 有的导弹。
输入导弹一次飞来的高度(雷达给出的高度不大于30000的正整数)。计算这套系统最多能拦截多少导弹。

输入

n颗依次飞来的导弹高度,导弹颗数<=1000。

输出

一套系统最多拦截的导弹数。

样例输入

7 300 250 275 252 200 138 245

样例输出

5
令f[i]表示前i个数的最长序列长度f[j]=max(f[j],f[i]+1)i<j且a[i]>=a[j]
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,a[1005],f[1005],ans;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        f[i]=1;
        for(int j=1;j<i;j++)
        if(a[j]>=a[i])f[i]=max(f[i],f[j]+1);
    }
    for(int i=1;i<=n;i++)
    ans=max(ans,f[i]);
    cout<<ans<<endl; 
 } 

但是在一些n=100000的题目上O(n^2)的算法会时间超限。我们考虑优化这一算法。令B[i]=长度位i的序列最后一个一个字符的最大值。

对于新进来的一个数,我们看其能否跟新B数组中的一个值。如何跟新一个值呢?二分查找。

#include<iostream>
#include<cstdio>
#include<algorithm> 
using namespace std;
int n,B[100005],a[100005],len;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    B[1]=-a[1],len=1;
    for(int i=2;i<=n;i++)
    {
        if(-a[i]>=B[len]) B[++len]=-a[i];
        else
        {
            int pos=upper_bound(B+1,B+len,-a[i])-B;
            B[pos]=-a[i];
        }
    }
    cout<<len<<endl;
}

就是很短的代码实现了nlogn的类lis功能。

 
原文地址:https://www.cnblogs.com/dancer16/p/7241509.html