POJ3903 Stock Exchange

  • 题目大意:求最长上升子序列……

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

  • 说一下该算法:令序列存于数组a中在O( n2 )的算法中,我们对于一个f[i]值的确定,需要扫描j=1->i-1的所有a[j]值,并取a[j] < <script type="math/tex" id="MathJax-Element-107"><</script>a[i]时的f[j]的最大值。试想如果存在两个个值x与y,满足x < <script type="math/tex" id="MathJax-Element-108"><</script>y < <script type="math/tex" id="MathJax-Element-109"><</script>i,x < <script type="math/tex" id="MathJax-Element-110"><</script>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] < <script type="math/tex" id="MathJax-Element-111"><</script>d[2]<… < <script type="math/tex" id="MathJax-Element-112"><</script>d[k-1] < <script type="math/tex" id="MathJax-Element-113"><</script>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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值