HDU - 6635

题目链接: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
//#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;
}

你可能感兴趣的:(HDU,随机化算法,LIS)