Description
题解
对于每个以
xi
结尾的最长上升序列长度
ai
一定是从i前面某个最长上升序列长度是
ai−1
的位置转移过来的。
我们需要求的是以
xi
开头的最长下降序列长度
bi
和最大,那么我们就应该让越后面的越小,但又有满足以
xi
结尾的最长上升序列长度为
ai
这个限制。
如果要是答案最大,就没有
xi
是相同的,不妨就将原序列看作是1到n的排列。
原序列
xi
的一些大小关系是可以确定的,
xi
一定要大于某个在i前面的
xj,满足aj+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);
}