LIS反链
直线上有n座山峰,第i座的高度为hi。从某座山峰上放飞一架纸飞机,它可以从左往右依次经过一系列高度严格递减的山头。
假设五座山峰的高度依次是3,4,3,2,1。从第一座山峰上放飞的纸飞机可以依次经过第一、四、五座山峰,但不能经过第二、三座山峰。
对于每座山峰,求出要经过除这座山峰外的每座山峰,至少需要放飞多少纸飞机。(每架纸飞机的起点可以不同)
输入描述:
第一行包括一个正整数n。
第二行包括n个正整数,第i个数表示第i座山峰的高度hi。
输出描述:
输出一行,包括n个用空格隔开的正整数,第i个数表示除去第i座山峰的答案。
输入
5
2 4 3 1 5
输出
2 3 3 3 2
即求除去i之后反链的长度。
设x[i]:以i为结尾的最长非降子序列长度
设y[i]:以i为开头的最长非降子序列长度
则包括a[i]的最长反链长度为x[i]+y[i]-1
如果该长度不等于a的最长反链长度len,则除去a[i]后反链长度不变,答案是len
否则
- 如果除去a[i]后反链长度-1的话,答案就是len-1
- 如果除去a[i]后反链长度不变,答案就是len
记录所有x[i]+y[i]-1== len时x[i]出现的次数,
如果x[i]出现次数大于1次,说明有另一条不包括i的最长反链:
设i、j都满足x[k]+y[k]-1=len且x[i]==x[j],要么j<i且链y[j]里不可能包括a[i](如果包括则y[j]>y[i]),要么i<j且链x[i]里不可能包括a[i](如果包括则x[j]>x[i]),所以,x[j]+y[j]-1这条反链不包括a[i],所以除去a[i]后还有另一条最长反链。
计算y时相当于反着计算x。
#include<bits/stdc++.h>
using namespace std;
char buf[1<<20],*_=buf,*__=buf;
#define gc() (_==__&&(__=(_=buf)+fread(buf,1,1<<20,stdin),_==__)?EOF:*_++)
#define TT template<class T>inline
TT bool read(T &x){
x=0;char c=gc();bool f=0;
while(c<48||c>57){if(c==EOF)return 0;f^=(c=='-'),c=gc();}
while(47<c&&c<58)x=(x<<3)+(x<<1)+(c^48),c=gc();
if(f)x=-x;return 1;
}
TT bool read(T&a,T&b){return read(a)&&read(b);}
TT bool read(T&a,T&b,T&c){return read(a)&&read(b)&&read(c);}
typedef long long ll;
const ll MAXN=1e6+8,mod=1e9+7,inf=0x3f3f3f3f;
int n,a[MAXN],k[MAXN],l;
int x[MAXN],y[MAXN],cnt[MAXN];
int main() {
read(n);
for(int i=0;i<n;++i)read(a[i]);
k[0]=a[0],l=1,x[0]=1;
for(int i=1,j;i<n;++i){
if(a[i]>=k[l-1])k[l]=a[i],x[i]=++l;
else{
j=upper_bound(k,k+l,a[i])-k;
k[j]=a[i];
x[i]=j+1;
}
}
k[0]=-a[n-1],l=1,y[n-1]=1;
for(int i=n-2,j;i>=0;--i){
if(a[i]<=-k[l-1])k[l]=-a[i],y[i]=++l;
else{
j=upper_bound(k,k+l,-a[i])-k;
k[j]=-a[i];
y[i]=j+1;
}
}
for(int i=0;i<n;++i){
if(x[i]+y[i]-1==l)cnt[x[i]]++;
}
for(int i=0;i<n;++i){
if(x[i]+y[i]-1==l){
if(cnt[x[i]]>1)printf("%d ",l);
else printf("%d ",l-1);
}else printf("%d ",l);
}
return 0;
}