题目链接:HDU - 6635
随机下,LIS长度的期望为 sqrt(n) ,那么我们考虑时光回溯,先求出一个LIS,然后如果当前删除的位置不在LIS上面,那么直接删掉即可,否则重新求LIS。
复杂度为:O(nsqrt(n)*log(n)),因为删除位置在LIS上面的期望为sqrt(n)。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=5e4+10;
int n,p[N],k[N],vis[N],res[N],d[N],mark[N],cnt,dp[N];
inline void LIS(){
memset(mark,0,sizeof mark); cnt=0; memset(dp,0,sizeof dp);
for(int i=1;i<=n;i++) if(!vis[i]){
if(!cnt||p[i]>d[cnt]) d[++cnt]=p[i],dp[i]=cnt;
else{
int pos=lower_bound(d+1,d+1+cnt,p[i])-d;
d[pos]=p[i]; dp[i]=pos;
}
}
int now=cnt,pre=n;
for(int i=n;i>=1;i--) if(dp[i]==now&&p[i]<=pre) mark[p[i]]=1,now--,pre=p[i];
}
inline void solve(){
cin>>n; memset(vis,0,sizeof vis);
for(int i=1;i<=n;i++) scanf("%d",&p[i]);
for(int i=1;i<=n;i++) scanf("%d",&k[i]);
LIS();
for(int i=n;i>=1;i--){
res[i]=cnt; vis[k[i]]=1;
if(mark[p[k[i]]]) LIS();
}
for(int i=1;i<=n;i++) printf("%d%c",res[i],i==n?'\n':' ');
}
signed main(){
int T; cin>>T; while(T--) solve();
return 0;
}