JZOJ3743. 【TJOI2014】Alice and Bob

Description

这里写图片描述

题解

对于每个以 xi 结尾的最长上升序列长度 ai 一定是从i前面某个最长上升序列长度是 ai1 的位置转移过来的。
我们需要求的是以 xi 开头的最长下降序列长度 bi 和最大,那么我们就应该让越后面的越小,但又有满足以 xi 结尾的最长上升序列长度为 ai 这个限制。
如果要是答案最大,就没有 xi 是相同的,不妨就将原序列看作是1到n的排列。
原序列 xi 的一些大小关系是可以确定的, xi 一定要大于某个在i前面的 xjaj+1=ai 。因为靠后面的数更小,所以这个j是最靠近i的那个j。
在满足这些条件后,越靠后的值越小。具体做法:j向i连一条边,表示 aj<ai ,在连完边之后就对这棵树遍历一下,每个点的访问顺序就是原序列的大小关系。
得到了原序列一行就可以求以 xi 开头的最长下降序列长度 bi 了。

code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100003
using namespace std;
int f[N],g[N],a[N],n,m,bz[N],t[N],tot,mx,l,r,mid,sum; 
int next[N],p[N];
long long ans;
void ins(int x,int y)
{
    next[++tot]=t[x];
    p[tot]=y;
    t[x]=tot;
}
void dfs(int x,int fa)
{
    a[x]=++sum;
    for(int i=t[x];i;i=next[i])
        if(p[i]!=fa)dfs(p[i],x);
} 
int main()
{
    freopen("alice.in","r",stdin);
    freopen("alice.out","w",stdout);
    memset(bz,0,sizeof(bz));
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        g[a[i]]=i;
        if(a[i]!=1)
        {
            ins(g[a[i]-1],g[a[i]]);
            bz[g[a[i]]]=1;
        }
    }
    for(int i=n;i;i--)
        if(bz[i]==0)dfs(i,0);

    tot=0;
    f[0]=-2147483647;
    for(int i=n;i;i--)
    {
        if(a[i]>f[tot])
        {
            tot++;
            f[tot]=a[i];
            ans+=tot;
            continue;
        }
        l=1;r=tot;
        while(l<r)
        {
            mid=(l+r)/2;
            if(f[mid]>a[i])r=mid;else l=mid+1;
        }
        ans+=l;
        f[l]=a[i];
    }
    printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值