zoukankan      html  css  js  c++  java
  • [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;
    }
  • 相关阅读:
    基于visual Studio2013解决C语言竞赛题之1074八皇后
    Bit,Bytes,KB,MB,GB,TB,PB,EB,ZB,YB
    RFID系统的选择
    java中复制文本文件
    java中复制文本文件
    数据筛选和排序
    实现Windows程序的数据绑定
    实现Windows程序的数据更新
    使用ListView控件展示数据
    构建良好的windows程序
  • 原文地址:https://www.cnblogs.com/evenbao/p/14359126.html
Copyright © 2011-2022 走看看