题目描述:
定义一个序列
x1,x2...xn
x
1
,
x
2
.
.
.
x
n
a序列
a1,a2...an
a
1
,
a
2
.
.
.
a
n
表示以i为结尾的最长上升子序列的长度
b序列
b1,b2...bn
b
1
,
b
2
.
.
.
b
n
表示以i为开头的最长下降子序列的长度
求在满足a序列的情况下
Max(∑ni=1bi)
M
a
x
(
∑
i
=
1
n
b
i
)
题目分析:
根据求LIS的方法,我们可以知道
若
ai
a
i
不为1,则存在一个
aj=ai−1
a
j
=
a
i
−
1
如果多个
ai
a
i
相同,那么我们尽量让后面的数小比较好
那么构造的方法就出来了
设定last[i]为
val=ai
v
a
l
=
a
i
出现的最后位置,我们从
last[ai−1]−>i
l
a
s
t
[
a
i
−
1
]
−
>
i
然后DFS,由于后加入的点在链表中的访问比先加入的点早,那么就满足了第二个条件,我们跑一边构造出的树,求出dfn即可
然后用树状数组求解答案
题目链接:
Ac 代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#define lowbit(x) (x&(-x))
const int maxm=1e5+100;
int num[maxm],tot;
int head[maxm],to[maxm<<1],net[maxm<<1],cnt;
int last[maxm],b[maxm],c[maxm];
int n;
inline void addedge(int u,int v)
{
to[++cnt]=v,net[cnt]=head[u],head[u]=cnt;
}
void dfs(int now)
{
b[now]=tot++;
for(int i=head[now];i;i=net[i]) dfs(to[i]);
}
inline void ins(int x,int val)
{
for(int i=x;i<=maxm;i+=lowbit(i))
c[i]=std::max(c[i],val);
}
inline int ask(int x)
{
int res=0;
for(int i=x;i;i-=lowbit(i))
res=std::max(res,c[i]);
return res;
}
int main()
{
scanf("%d",&n);
last[0]=n+1;
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
addedge(last[x-1],i);
last[x]=i;
}
dfs(n+1);
long long ans=0;
for(int i=n;i>=1;i--)
{
int poi=ask(b[i]-1)+1;
ans+=(long long)poi;
ins(b[i],poi);
}
printf("%lld\n",ans);
return 0;
}