最长上升子序列

题目地址:https://vjudge.net/problem/428698/origin
Peter has a sequence a1,a2,...,ana1,a2,...,an and he define a function on the sequence -- F(a1,a2,...,an)=(f1,f2,...,fn)F(a1,a2,...,an)=(f1,f2,...,fn), where fifi is the length of the longest increasing subsequence ending with aiai. 

Peter would like to find another sequence b1,b2,...,bnb1,b2,...,bn in such a manner that F(a1,a2,...,an)F(a1,a2,...,an) equals to F(b1,b2,...,bn)F(b1,b2,...,bn). Among all the possible sequences consisting of only positive integers, Peter wants the lexicographically smallest one. 

The sequence a1,a2,...,ana1,a2,...,an is lexicographically smaller than sequence b1,b2,...,bnb1,b2,...,bn, if there is such number ii from 11 to nn, that ak=bkak=bk for 1k<i1≤k<i and ai<biai<bi.

InputThere are multiple test cases. The first line of input contains an integer TT, indicating the number of test cases. For each test case: 

The first contains an integer n(1n100000)(1≤n≤100000) -- the length of the sequence. The second line contains nn integers a1,a2,...,ana1,a2,...,an (1ai109)(1≤ai≤109).
OutputFor each test case, output nn integers b1,b2,...,bnb1,b2,...,bn (1bi109)(1≤bi≤109) denoting the lexicographically smallest sequence. 
Sample Input

3
1
10
5
5 4 3 2 1
3
1 3 5

Sample Output

1
1 1 1 1 1
1 2 3

解法1:

摘自大神的 lower——bound解释

函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置

举例如下:

一个数组number序列为:4,10,11,30,69,70,96,100.设要插入数字3,9,111.pos为要插入的位置的下标

pos = lower_bound( number, number + 8, 3) - number,pos = 0.即number数组的下标为0的位置。

pos = lower_bound( number, number + 8, 9) - number, pos = 1,即number数组的下标为1的位置(即10所在的位置)。

pos = lower_bound( number, number + 8, 111) - number, pos = 8,即number数组的下标为8的位置(但下标上限为7,所以返回最后一个元素的下一个元素)。

所以,要记住:函数lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置,且last的位置是越界的!!~

返回查找元素的第一个可安插位置,也就是“元素值>=查找值”的第一个元素的位置

 

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <limits.h>
#define MAX 100005
using namespace std;
int dp[MAX],a[MAX],b[MAX];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        for(int i=1;i<=n;i++)
            b[i]=INT_MAX;

        for(int i=1;i<=n;i++)
        {
            int pos=lower_bound(b+1,b+n+1,a[i])-b;
            dp[i]=pos;
            b[pos]=a[i];
        }

        for(int i=1;i<=n-1;i++)
            printf("%d ",dp[i]);
        printf("%d\n",dp[n]);
    }
    return 0;
}

解法二:

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

int number[100005],dp[100005],inc[100005];

int main()
{
    int n,length,low,high,tail,mid;
    scanf("%d",&n);
    while (n--)
    {
        tail = dp[0] = 0;
        scanf("%d",&length);
        for (int i = 1; i <= length; i++)
        {
            scanf("%d",&number[i]);
            low = 0;
            high = tail - 1;
            while (high >= low)
            {
                mid = (low + high) / 2;
                if (dp[mid] >= number[i])
                {
                    high = mid - 1;
                }
                else
                {
                    low = mid + 1;
                }
            }
            if (low >= tail)
            {
                tail++;
            }
            dp[low] = number[i];
            inc[i] = low + 1;
        }
        printf("%d",inc[1]);
        for (int l = 2; l <= length; l++)
        {
            printf(" %d",inc[l]);
        }
        printf("\n");
    }
    return 0;
}

 

posted @ 2017-02-15 08:48  呆毛王王负剑  阅读(32)  评论(0)    收藏  举报