• [CF568E] Longest Increasing Subsequence


    [题目链接]

    https://codeforces.com/contest/568/problem/E

    [题解]

    首先注意到一个数最多出现在一个上升子序列中 , 故可以忽略重复数字的影响。

    不妨令 (l_{i} , p_{i}) 分别表示当 (i) 非 "空" 时 , 以 (i) 为结尾的最长上升子序列长度和上一项的位置。

    接着 , 令 (f_{i} , g_{i}) 表示长度为 (i) 的最长上升子序列长度和最后一项位置。

    从前到后以此加数 , 假设当前加入的是第 (i) 个数。

    (i) 非 "空" , 考虑经典的 (O(NlogN)) 求解 (LIS) 做法。 设当前位置上的数为 (x) , 那么在 (f) 上找到 (< x) 的最大 (f_{j}) , 并令 (l_{i} = j + 1) , (p_{i} = g_{j}) , (g_{j + 1} = i)

    若该位置空缺 , 则从大到小枚举可插入的数并更新 (f , g) 数组。这样避免了二分的问题 , 只需用一个指针扫描即可。

    这样就可以计算出最长上升子序列的长度了。

    接着考虑还原序列 , 不妨倒着考虑 , 设此时已经还原到了第 (i) 个数 (x) , 其在原序列中位置为 (j)

    若该位置非空 , 则可以直接用 (p_{j}) 找到上一个数。

    否则 , 现在 (j) 前找到第一个数 (s) 使得 (l_{s} = i - 1)(s) 上的数比 (x) 小 , 如果找不到 , 上一个位置就是上一个空位 , 其权值为 (< x) 的最大值。

    时间复杂度 : (O(NlogN + K(N + M)))

    [代码]

    # include <bits/stdc++.h>
     
    using namespace std;
     
    typedef long long LL;
     
    const int MN = 2e5 + 5 , INF = 2e9;
     
    int N , M , vis[MN] , A[MN] , F[MN] , L[MN] , G[MN] , P[MN] , ans[MN] , B[MN];
     
    inline void get(int i , int k , int &x) {
    	int o = lower_bound(B + 1 , B + 1 + M , k) - B - 1;
    	vis[o] = 1; x = ans[i] = B[o];
    }
     
    int main() {
    	
    	scanf("%d" , &N); 
    	for (int i = 1; i <= N; ++i) scanf("%d" , &A[i]) , F[i] = INF;
    	++N , A[N] = F[N] = INF;
    	scanf("%d" , &M);
    	for (int i = 1; i <= M; ++i) scanf("%d" , &B[i]);
    	sort(B + 1 , B + 1 + M);
    	for (int i = 1; i <= N; ++i) 
    		if (~A[i]) {
    			int j = lower_bound(F + 1 , F + 1 + N , A[i]) - F - 1;
    			L[i] = j + 1 , P[i] = G[j] , F[j + 1] = A[i] , G[j + 1] = i;
    	    } else {
    	    	for (int j = N , o = M; o; --o) {
    	    		while (F[j] >= B[o]) --j;
    	    		F[j + 1] = B[o] , G[j + 1] = i;
    	    	}
    	    }
    	int i = L[N] , j = N , x = A[N];
    	while (i--) {
    		if (~A[j]) {
    			if (!~A[P[j]]) get(P[j] , A[j] , x);
    			else x = A[P[j]];
    			j = P[j];
    		} else {
    			bool ok = 0;
    			for (int s = j - 1; s; --s) 
    				if (~A[s] && L[s] == i && A[s] < x) {
    					x = A[j = s] , ok = 1;
    					break;
    				}
    			if (ok) continue;
    			for (int s = j - 1; s; --s) 
    				if (!~A[s]) {
    					get(s , x , x); j = s;
    					break;
    				}
    		}
    	}
    	for (int i = 1 , j = 1; i <= N; ++i) {
    		if (!~A[i]) {
    			if (ans[i]) continue;
    			while (vis[j]) ++j;
    			vis[j] = 1 , ans[i] = B[j];
    		} else ans[i] = A[i];
    	}
    	for (int i = 1; i < N; ++i) printf("%d " , ans[i]);
    	printf("
    ");
        return 0;
    }
  • 相关阅读:
    mysql 优化20点
    java function
    设计模式 概览
    Linux安装java1.8并配置环境变量
    windows下一次执行多个sql文件
    mybatis查询结果为空时的返回值问题
    Java中Json与String互转
    SSM Service自动注入失败
    本地安装Mysql5.7过程中出现的一系列问题
    解决本地工具无法连接服务器上的mysql的问题
  • 原文地址:https://www.cnblogs.com/evenbao/p/14359126.html
Copyright © 2020-2023  润新知