版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/86562237
BZOJ传送门
洛谷传送门
解析:
其实就是加了特技的拓扑排序。
首先我们肯定可以确定一些位置的大小关系,连边建图后肯定是一个DAG,这时候应该都想得到拓扑排序。
但是我们同时需要令 序列之和尽量大,换句话说,就是大的数尽量向前放,小的数尽量向后放。
只需要在拓扑排序的时候加一个优先队列来维护就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define pc putchar
#define cs const
namespace IO{
namespace IOONLY{
cs int Rlen=1<<18|1;
char buf[Rlen],*p1,*p2;
}
inline char get_char(){
using namespace IOONLY;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int N=100005;
int n,A[N];
int last[N],nxt[N<<1],to[N<<1],ecnt,deg[N];
inline void addedge(int u,int v){
nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;deg[v]++;
}
int dfn[N];
set<int> q;
inline void topsort(){
for(int re i=1;i<=n;++i)if(!deg[i])q.insert(i);
int topsort_clock=0;
while(!q.empty()){
int u=*q.begin();q.erase(q.begin());
dfn[u]=n-(topsort_clock++);
for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]])
if(0==--deg[v])q.insert(v);
}
}
int a[N],len;
inline ll calc(){
topsort();
a[len=1]=dfn[n];
ll ans=1;
for(int re i=n-1;i;--i){
int x=dfn[i];
if(x>a[len]){
a[++len]=x;
ans+=len;
}
else {
int pos=lower_bound(a+1,a+len+1,x)-a;
a[pos]=x;
ans+=pos;
}
}
return ans;
}
int s[N];
signed main(){
n=getint();
for(int re i=1;i<=n;A[i++]=getint());
for(int re i=1;i<=n;++i){
if(s[A[i]])addedge(s[A[i]],i);
if(A[i]>1)addedge(i,s[A[i]-1]);
s[A[i]]=i;
}
cout<<calc();
return 0;
}