POJ 2533 - Longest Ordered Subsequence - [最长递增子序列长度][LIS问题]

题目连接:http://poj.org/problem?id=2533c++

Time Limit: 2000MS Memory Limit: 65536Kspa

Descriptioncode

A numeric sequence of  ai is ordered if  a1 <  a2 < ... <  aN. Let the subsequence of the given numeric sequence ( a1a2, ...,  aN) be any sequence ( ai1ai2, ...,  aiK), where 1 <=  i1 <  i2 < ... <  iK <=  N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, e. g., (1, 7), (3, 4, 8) and many others. All longest ordered subsequences are of length 4, e. g., (1, 3, 5, 8).

Your program, when given the numeric sequence, must find the length of its longest ordered subsequence.

Inputblog

The first line of input file contains the length of sequence N. The second line contains the elements of sequence - N integers in the range from 0 to 10000 each, separated by spaces. 1 <= N <= 1000

Outputip

Output file must contain a single integer - the length of the longest ordered subsequence of the given sequence.

Sample Inputci

7
1 7 3 5 9 4 8

Sample Outputelement

4

 

题意:get

给定长度为 $N$ 的一串整数序列 $a[1 \sim N]$,求其最长上升子序列的长度。input

注意:子序列能够不连续,要求严格单增。it

 

题解:

$O(n \log n)$ 解法——贪心+二分。

构建一个栈 $S$ 和一个变量 $top$ 表明栈顶位置,该栈的表明:栈中的第 $i$ 个数 $S[i]$,是序列 $a$ 中,长度为 $i$ 的递增子序列的末尾元素。

初始化 S[top=1]=a[1] ,即将第一个数字入栈;这很好理解,到目前为止 $a[1]$ 本身是一个长度为 $1$ 的递增子序列。

遍历 $a[ i = 2 \sim N ]$:每次对于 $a[i]$,找出栈 $S[1 \sim top]$ 中第一个大于等于 $a[i]$ 的数的位置 $pos$,若不存在则返回 $pos=top+1$。

这是因为,若存在第一个大于等于 $a[i]$ 的数 $S[pos]$ ,说明对于长度为 $pos$ 的递增子序列,能够用 $a[i]$ 代替掉其原来的末尾元素 $S[pos]$,这样一来,依然是一个长度为 $pos$ 的递增子序列,并且该递增子序列被进一步“加长”的潜力增长。而若是栈中不存在大于等于 $a[i]$ 的数,这说明我能够在目前长度为 $top$ 的递增子序列后面加上一个 $a[i]$,那么咱们就获得了一个以 $a[i]$ 为结尾的,长度为 $top+1$ 的递增子序列。

所以,咱们把 $S[pos]$ 更新为 $a[i]$,而且尝试更新栈的大小 if(pos>top) top=pos;  。

因为栈 $S$ 中元素始终保持单调递增(并且栈内元素互不相等),因此找 $S$ 中第一个大于等于 $a[i]$ 的数能够使用二分查找。

 

AC代码(在OpenJudge百练提交):

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+5;

int n;
vector<int> a;

int S[maxn],top;
int LIS(const vector<int>& a)
{
    S[top=0]=a[0];
    for(int i=0;i<a.size();i++)
    {
        int pos=lower_bound(S,S+top+1,a[i])-S;
        S[pos]=a[i], top=max(top,pos);
    }
    return top+1;
}

int main()
{
    cin>>n;
    while(n--)
    {
        int x; cin>>x;
        a.push_back(x);
    }
    cout<<LIS(a)<<endl;
}

PS.咱们能够看到,求第一个大于等于 $a[i]$ 的数使用了lower_bound,相应的若是咱们使用upper_bound会怎么样呢?不难证实,咱们将会获得最长不降低子序列的长度。

相关文章
相关标签/搜索