zoukankan      html  css  js  c++  java
  • Codeforces 568E. Longest Increasing Subsequence 题解

    题目链接:E. Longest Increasing Subsequence

    题目大意:洛谷


    题解:首先如果要求的是最长上升子序列的长度是很简单的。

    因为是严格单调递增,所以每一个数在最长上升子序列中最多只会出现一次,所以对于(b)数组中的每一个数只能够取一次的限制可以不考虑,直接考虑传统的(O(nlog n))做法,那么对于正常的位置,正常地二分做,对于(-1)的位置,可以枚举当前位置选哪一个做。

    这一部分的时间复杂度是(O(nlog n+mk))的。

    接下来考虑还原方案。

    先考虑没有(-1)的情况。

    因为不是(O(n^2))的 DP,所以我们在转移(其实就是二分查找中的那一步,姑且称之为转移吧)的时候需要记录它的上一个位置,这样的话我们就可以倒推出来原序列的长度了。

    因为如果需要找最大值的位置的话比较麻烦,所以我们可以直接在序列末尾添加上一个( ext{Inf})

    接下来考虑(-1)应当怎么处理。

    直接在(b)数组中找到小于当前数的最大的数填进去就可以了。

    总时间复杂度(O(nlog n +mlog m +(n+m)k))

    代码:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    void read(int &a){
    	a=0;
    	int f=1;
    	char c=getchar();
    	while(c<'0'||c>'9'){
    		if(c=='-'){
    			f=-1;
    		}
    		c=getchar();
    	}
    	while(c>='0'&&c<='9'){
    		a=(a<<1)+(a<<3)+(c^48);
    		c=getchar();
    	}
    	if(f==-1){
    		a=-a;
    	}
    }
    const int Maxn=100000;
    const int Maxk=1000;
    const int Inf=0x7f7f7f7f;
    int n,m;
    int a[Maxn+5],b[Maxn+5];
    bool vis[Maxn+5];
    int f[Maxn+5];
    int g[Maxn+5];
    int p[Maxn+5],pos[Maxn+5];
    int ans[Maxn+5];
    void get(int i,int k,int &x){
    	int tmp=lower_bound(b+1,b+1+m,k)-b-1;
    	vis[tmp]=1;
    	x=ans[i]=b[tmp];
    }
    int main(){
    	read(n);
    	for(int i=1;i<=n;i++){
    		read(a[i]);
    		f[i]=Inf;
    	}
    	n++;
    	a[n]=Inf;
    	f[n]=Inf;
    	read(m);
    	for(int i=1;i<=m;i++){
    		read(b[i]);
    	}
    	sort(b+1,b+1+m);
    	for(int i=1;i<=n;i++){
    		if(a[i]==-1){
    			for(int j=n,k=m;k>0;k--){
    				while(f[j]>=b[k]){
    					j--;
    				}
    				f[j+1]=b[k];
    				pos[j+1]=i;
    			}
    		}
    		else{
    			int j=lower_bound(f+1,f+1+n,a[i])-f-1;
    			g[i]=j+1;
    			p[i]=pos[j];
    			f[j+1]=a[i];
    			pos[j+1]=i;
    		}
    	}
    	{
    		int i=g[n],j=n,x=a[n];
    		while(i--){
    			if(a[j]!=-1){
    				if(a[p[j]]==-1){
    					get(p[j],a[j],x);
    				}
    				else{
    					x=a[p[j]];
    				}
    				j=p[j];
    			}
    			else{
    				bool flag=0;
    				for(int s=j-1;s>0;s--){
    					if(a[s]!=-1&&g[s]==i&&a[s]<x){
    						x=a[j=s];
    						flag=1;
    						break;
    					}
    				}
    				if(flag){
    					continue;
    				}
    				for(int s=j-1;s>0;s--){
    					if(a[s]==-1){
    						get(s,x,x);
    						j=s;
    						break;
    					}
    				}
    			}
    		}
    	}
    	for(int i=1,j=1;i<n;i++){
    		if(a[i]==-1){
    			if(ans[i]!=0){
    				a[i]=ans[i];
    				continue;
    			}
    			while(vis[j]){
    				j++;
    			}
    			vis[j]=1;
    			a[i]=b[j];
    		}
    	}
    	for(int i=1;i<n;i++){
    		printf("%d ",a[i]);
    	}
    	puts("");
    	return 0;
    }
    
    本博客欢迎转载,转载请注明文章出处作者
  • 相关阅读:
    PHP设计模式
    秒杀方案
    lua 安装
    docker 相关命令
    dockerfile
    JS工具对象 DATE 方法
    JS工具对象 Array
    JS工具对象 String 10种常用 方法
    工具对象
    JS工具对象Math 7个常用 方法
  • 原文地址:https://www.cnblogs.com/withhope/p/13568057.html
Copyright © 2011-2022 走看看