JZOJ3743. 【TJOI2014】Alice and Bob

本文介绍了一种求解最长上升及下降子序列长度之和的算法。通过对原序列进行特定处理,构建图并遍历,得到各元素对应的最长下降序列长度。最终通过动态规划求得总和最大值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值