POJ3903 Stock Exchange

来源:互联网 发布:精通python网络爬虫pdf 编辑:程序博客网 时间:2024/06/06 04:49
  • 题目大意:求最长上升子序列……

  • 思路:看这数据规模,L<=100000,还一个点多组测试数据,O(n2)的是不用指望了,于是要使用O(nlogn)的算法。

  • 说一下该算法:令序列存于数组a中在O(n2)的算法中,我们对于一个f[i]值的确定,需要扫描j=1->i-1的所有a[j]值,并取a[j]<a[i]时的f[j]的最大值。试想如果存在两个个值x与y,满足x<y<i,x<y,且f[x]=f[y],在构建序列的过程中,我们应该选择x还是y?显然,应该是x,因为在a[x]至a[i]中可能存在一个可以用于构建序列的元素。对于任意的满足f[t]=某一值k的所有a[t],我们记d[k]=min(a[t]),即表示从1至某一位置最长上升子序列长度为k的末尾元素值的最小值,于是可以发现,对于序列d,有d[1]<d[2]<…<d[k-1]<d[k],因为我们保存的都是最小元素值,每增加序列长度,放在最后的元素,因为是上升子序列,必然比原先的末尾元素大。于是我们得出这样一个策略,对于已经求出的长度为len(注意,是已经求出)的序列,对于某个元素a[t],如果a[t]>d[len],只需令a[t]接在d[len]之后,然后len++,即此时序列长度得到增加;否则,在序列d中寻找满足a[t]>d[j]的最大的j,令d[j+1]=a[t],但是因为序列长度没有增加,所以对len无操作。实际操作时,只需枚举序列中的每一个元素,这是O(n)的,在寻找元素插入位置时,由于d具有单调性,我们可以利用二分查找,这是O(logn)的。于是,总时间复杂度降至O(nlogn)。

  • 代码如下:

#include<iostream>#include<cstdio>using namespace std;const int maxl=100005;int l,a[maxl],c[maxl];int find(int l,int r,int x){    int mid=(l+r)/2;    if (l==r)      return l;    if (c[mid]>x)      return find(l,mid,x);    else       return find(mid+1,r,x); }void work(){    int len=0,j;    c[1]=-10000;    for (int i=1;i<=l;++i)    {        if (a[i]>c[len])          j=++len;        else j=find(1,len,a[i]);        c[j]=a[i];    }    printf("%d\n",len);}void init(){    while (scanf("%d",&l)==1)    {        for (int i=1;i<=l;++i)          scanf("%d",&a[i]);        work();    }}int main(){    init();    return 0;}
0 0
原创粉丝点击