POJ 1631(最长上升子序列 nlogn).

~~~~

由题意可知,因为左边是按1~n的顺序递增排列,要想得到不相交组合,左边后面的一定与相应右边后面的相连,如此一来,

就可以发现其实是一道最长上升子序列的题目,要注意的是N<40000,用n^2的算法一定会超时。

题目链接:http://poj.org/problem?id=1631

~~~~

nlogn的算法在这里补充一下。

最长不下降子序列的O(nlogn)算法分析如下:

设 A[t]表示序列中的第t个数,F[t]表示从1到t这一段中以t结尾的最长上升子序列的长度,初始时设F [t] = 0(t = 1, 2, ..., len(A))。则有动态规划方程:F[t] = max{1, F[j] + 1} (j = 1, 2, ..., t - 1, 且A[j] < A[t])。

现在,我们仔细考虑计算F[t]时的情况。假设有两个元素A[x]和A[y],满足

(1)x < y < t

(2)A[x] < A[y] < A[t]

(3)F[x] = F[y]

此时,选择F[x]和选择F[y]都可以得到同样的F[t]值,那么,在最长上升子序列的这个位置中,应该选择A[x]还是应该选择A[y]呢?

很明显,选择A[x]比选择A[y]要好。因为由于条件(2),在A[x+1] ... A[t-1]这一段中,如果存在A[z],A[x] < A[z] < a[y],则与选择A[y]相比,将会得到更长的上升子序列。

再根据条件(3),我们会得到一个启示:根据F[]的值进行分类。对于F[]的每一个取值k,我们只需要保留满足F[t] = k的所有A[t]中的最小值。设D[k]记录这个值,即D[k] = min{A[t]} (F[t] = k)。

注意到D[]的两个特点:

(1) D[k]的值是在整个计算过程中是单调不下降的。

(2) D[]的值是有序的,即D[1] < D[2] < D[3] < ... < D[n]。

利 用D[],我们可以得到另外一种计算最长上升子序列长度的方法。设当前已经求出的最长上升子序列长度为len。先判断A[t]与D[len]。若A [t] > D[len],则将A[t]接在D[len]后将得到一个更长的上升子序列,len = len + 1, D[len] = A [t];否则,在D[1]..D[len]中,找到最大的j,满足D[j] < A[t]。令k = j + 1,则有A [t] <= D[k],将A[t]接在D[j]后将得到一个更长的上升子序列,更新D[k] = A[t]。最后,len即为所要求的最长上
升子序列的长度。

在 上述算法中,若使用朴素的顺序查找在D[1]..D[len]查找,由于共有O(n)个元素需要计算,每次计算时的复杂度是O(n),则整个算法的 时间复杂度为O(n^2),与原来的算法相比没有任何进步。但是由于D[]的特点(2),我们在D[]中查找时,可以使用二分查找高效地完成,则整个算法 的时间复杂度下降为O(nlogn),有了非常显著的提高。需要注意的是,D[]在算法结束后记录的并不是一个符合题意的最长上升子序列!

~~~~

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define N 44444
using namespace std;

int f[N];
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,c=0;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            int t;
            scanf("%d",&t);
            if(i==1) f[++c]=t;
            else
            {
                if(t>f[c]) f[++c]=t;
                else
                {
                    int pos=lower_bound(f+1,f+c,t)-f;
                    f[pos]=t;
                }
            }
        }
        printf("%d\n",c);
    }
    return 0;
}

POJ 1631(最长上升子序列 nlogn).,布布扣,bubuko.com

时间: 2024-12-20 11:55:07

POJ 1631(最长上升子序列 nlogn).的相关文章

Bridging signals POJ 1631(最长递增子序列dp)

原题 题目链接 题目分析 由题目知,如果能求出连接点的最长递增子序列,则可以把连接不在该序列中的点的线全部剪掉.而维护最长递增子序列可以用dp来做,考虑到相同长度的递增子序列末尾数字越小越好,可以这样定义dp,dp[i]长度为i的递增子序列的最小末尾值,初始化为INF,由于这个dp具有有序性,因此可以用二分来加快更新,每次遍历到值num[i],只需二分找出大于等于num[i]的更新之即可.最后从扫一遍dp数组即可得到最长长度. 代码 1 #include <iostream> 2 #inclu

POJ 1631 最长上升子序列的O(nlogn)算法

用普通的O(n^2)方法会超时,于是在网上习得O(nlogn)的算法. 1 #include<algorithm> 2 #include<cstdio> 3 #include<vector> 4 using namespace std; 5 6 int a[40000]; 7 vector<int> dp; 8 int main() 9 { 10 int t; 11 scanf("%d",&t); 12 while(t--) 13

poj 3903 &amp; poj 2533 最长上升子序列(LIS)

最长上升子序列. 做这道题之前先做了2533,再看这道题,感觉两道题就一模一样,于是用2533的代码直接交, TLE了: 回头一看,数据范围.2533 N:0~1000:3903 N :1~100000. 原因终归于算法时间复杂度. 也借这道题学习了nlgn的最长上升子序列.(学习链接:http://blog.csdn.net/dangwenliang/article/details/5728363) 下面简单介绍n^2 和 nlgn 的两种算法. n^2: 主要思想:DP: 假设A1,A2..

最长上升子序列 nlogn

最长上升子序列中对于数ipt[i],向前遍历,当数ipt[j]小于ipt[i] 则ipt[j]可作为上升序列中ipt[i]的前一个数字 dp[i] = max{ dp[j] + 1 | j < i && ipt[j] < ipt[i]} 若现在有两个状态a,b 满足dp[a] = dp[b]且 ipt[a] < ipt[b]  则对于后面的状态dp[a]更优  因为若ipt[i] > dp[b] 则必然ipt[i] > dp[a],反之若ipt[i] >

poj之最长公共子序列

题目:poj 1458   Common Subsequence Description A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is a subsequenc

poj之最长递增子序列

题目:POJ 2533   Longest Ordered Subsequence Description A numeric sequence of ai is ordered if a1 < a2 < ... < aN. Let the subsequence of the given numeric sequence (a1, a2, ..., aN) be any sequence (ai1, ai2, ..., aiK), where 1 <= i1 < i2 &l

hdu 1025 Constructing Roads In JGShining&#39;s Kingdom(最长上升子序列nlogn算法)

学习了最长上升子序列,刚开始学的n^2的方法,然后就超时了,肯定超的,最大值都是500000,平方之后都12位 了,所以又开始学nlogn算法,找到了学长党姐的博客orz,看到了rating是浮云...确实啊,这些不必太关 注,作为一个动力就可以啦.没必要看的太重,重要的事学习知识. 思路: 这道题目可以先对一行排序,然后对另一行求最长上升子序列... n^2算法: 序列a[n],设一个数组d[n]表示到n位的时候最长公共子序列(此序列包括n),所以呢 d[n]=max(d[j]+1,0<j<

Longest Ordered Subsequence POJ - 2533 最长上升子序列dp

题意:最长上升子序列nlogn写法 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int dp[1005]; 7 int a[1005]; 8 int main(){ 9 int n; 10 while(cin>>n){ 11 for(int i=0;i<n;i++){ 12

最长公共子序列 nlogn

先来个板子 #include<bits/stdc++.h> using namespace std; const int N = 1e6+20, M = 1e6+10, mod = 1e9+7, inf = 1e9+1000; typedef long long ll; struct node { int c; int num; } u[N]; int i,j,k = 0,n,m,x,y = 0,T = 0,ans = 0,big = 0,cas = 0,num = 0,len = 0; bo