BZOJ3173 [Tjoi2013]最长上升子序列

3 篇文章 0 订阅

BZOJ3173 [Tjoi2013]最长上升子序列

Description

将1到N插入序列中,接下是N个数字,第k个数字Xk,表示我们将k插入到位置Xk(0<=Xk<=k-1,1<=k<=N)求每一次插入的LIS

题解

每一次插入的数是递增的,所以我们知道对于一个数x,再最终数列的位置为 Dx ,
那么

f[Dx]=max(f[Dx],f[Dx1])

为什么可以直接从最终序列来计算呢?
因为每次插入的X比已经插入的序列任意一个数都大,所以
对于X右边的数,肯定无影响。
对于X左边的数,影响的就是以X结尾的最终序列的LIS。
所以每次加入一个数,会产生一个在最终序列中以其结尾的LIS。
我们就要判断这个新产生的序列是否比加这个数之前的所有LIS长,类似于前缀的
方法统计每插入一个数得到的LIS。

所以关键是怎么求出这个最终序列,正解是用平衡树来求。然而数据比较水(其实是我不会treap),用vector可以水过。(笑~)

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <vector>
#define MAXN 1000000+10
using namespace std;

int n,a[MAXN],f[MAXN],ans[MAXN],top=1;
int s[MAXN],d[MAXN];
vector<int> v;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x;
        scanf("%d",&x);
        v.insert(v.begin()+x,i);
    }
    for(int i=1;i<=n;i++) d[v[i-1]]=i,a[i]=v[i-1];
    top=1;s[top]=a[1];f[1]=1;

    for(int i=2;i<=n;i++)
    {
        if(a[i]>s[top]) s[++top]=a[i],f[i]=top;
        else 
        {
            int k=lower_bound(s+1,s+top+1,a[i])-s;
            s[k]=a[i],f[i]=k;
        }
    }
    for(int i=1;i<=n;i++)
    {
        f[d[i]]=max(f[d[i]],f[d[i-1]]);
        printf("%d\n",f[d[i]]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值