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

题意:最长上升子序列。复杂度为O(n*logn).

思路:这道题只能用nlogn的算法,n^2的话会卡掉。

下面这两个个链接介绍nlogn的算法讲的还可以。

http://www.cnblogs.com/celia01/archive/2012/07/27/2611043.html

http://blog.sina.com.cn/s/blog_4b1e4fe9010098af.html

代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=40005;
int n,a[maxn],d[maxn];

int binarysearch(int l,int r,int p)
{
    int mid=(l+r)/2;
    while(l<=r)
    {
        if(d[mid]<p && p<=d[mid+1])
           return mid;
        if(d[mid]<p) l=mid+1;
        else r=mid-1;
        mid=(l+r)/2;
    }
}
int solve()
{
    int len=1;
    d[1]=a[1];
    for(int i=2;i<=n;i++)
    {
        if(a[i]>d[len])
        {
            len++;
            d[len]=a[i];
        }
        else
        {
            int k=binarysearch(1,len,a[i]);
            d[k+1]=a[i];
        }
    }
    return len;
}
int main()
{
//    freopen("ine.cpp","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        printf("%d\n",solve());
    }
    return 0;
}
View Code

 

上面这个写法比较好懂,《训练指南》上讲了另一种写法,短了很多。

如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=40005;
const int INF=1000000;
int n,a[maxn],d[maxn];

int main()
{
//    freopen("ine.cpp","r",stdin);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        fill(d,d+n,INF);
        for(int i=1;i<=n;i++)
            *lower_bound(d,d+n,a[i])=a[i];
        printf("%d\n",lower_bound(d,d+n,INF)-d);
    }
    return 0;
}
View Code

 

上面使用的STL中的fill()函数和lower_bound()函数。

简略简绍下。

fill()函数它的原理是把那一块单元赋成指定的值,与memset不同,
memset则是按字节填充的。

例如:

int main()
{
    int  d[100];
    fill(d,d+100,1);
    for(int i=0; i<100; i++)
        cout<<d[i]<<" ";
    cout<<endl;
    memset(d,1,100*sizeof(int));
    for(int i=0; i<100; i++)
        cout<<d[i]<<" ";
    cout<<endl;
}

使用fill()函数,数组d[]中的元素都赋值为数字1,使用memset()函数,数组d[]中的元素都赋值为数字(1<<24)+(1<<16)+(1<<8)+1  =  16843009.

 

iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。

iterator upper_bound( const key_type &key ):返回一个迭代器,指向键值> key的第一个元素。

lower_bound()在 [first , last) 这个前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置。如果所有元素都小于val,则返回last的位置。(注意:此时数组下标越界)

upper_bound()也是在 [first , last) 这个前闭后开区间进行二分查找,如果插入元素大于数组中全部元素,返回的是last。注意:此时数组下标越界)

 

 posted on 2013-08-19 15:51  ∑求和  阅读(184)  评论(0编辑  收藏  举报