CF568E Longest Increasing Subsequence 題解
阿新 • • 發佈:2020-08-29
CF568E Longest Increasing Subsequence
首先重複填數對答案沒有影響\(,\)所以先忽略這個條件\(.\)
記\(f_i\)為 以i為結尾的LIS的長度\(,\) \(g_i\) 為以i為結尾的LIS的上一位\(.\)
記\(Min_x\)為 當前長度為\(x\)的LIS的最小的結尾 \(pos_x\)當前長度為\(x\)的LIS的最小的結尾的位置\(.\)
這些都可以簡單\(dp\)出來\(.\)
然後我們考慮怎麼構造方案\(.\)
不是\(-1\)的位置\(x\)我們可以直接跳到\(g_x\) \(.\)
如果\(x\)所在的位置是\(-1,\)那麼我們優先找\(a_y ≠ -1 ,\)
否則\(,\)我們就只能跳到最近的一個\(-1\)的位置\(.\)
\(O(n\log n+m\log m+(n+m)k)\)
程式碼\(:\)
#include <bits/stdc++.h> using namespace std; template <typename T> void read(T &x){ x = 0; int f = 1; char ch = getchar(); while (!isdigit(ch)) {if (ch == '-') f = -1; ch = getchar();} while (isdigit(ch)) {x = x * 10 + ch - '0'; ch = getchar();} x *= f; } inline void write(int x){if (x > 9) write(x/10); putchar(x%10+'0'); } const int N = 100005,M = 100005,INF = 1e9 + 9; int mn[N],pos[N],mx; int n,a[N],f[N],g[N],m,b[M]; int main(){ register int i,j,p; read(n); for (i = 1; i <= n; ++i) read(a[i]),mn[i] = INF; a[++n] = INF-1; mn[n] = INF; read(m); for (i = 1; i <= m; ++i) read(b[i]); sort(b+1,b+m+1); for (i = 1; i <= n; ++i){ if (a[i] != -1){ p = lower_bound(mn,mn+mx+1,a[i]) - mn; if (p > mx) ++mx; if (a[i] < mn[p]) mn[p] = a[i],pos[p] = i; f[i] = p,g[i] = pos[p-1]; continue; } for (p = mx+1,j = m; j ; --j){ while (p && b[j] <= mn[p-1]) --p; if (b[j] < mn[p]) mn[p] = b[j],pos[p] = i; } f[i] = -1; if (pos[mx+1]) ++mx; } int now = n,nowlen = f[n],nowv = a[n]; while (nowlen){ if (a[now] != -1){ --nowlen,nowv = a[now],now = g[now]; continue; } for (i = m; i ; --i) if (b[i] != -1 && b[i] < nowv){ a[now] = b[i]; b[i] = -1; break; } for (i = now-1; i ; --i) if (f[i] == nowlen-1 && a[i] < a[now]){ g[now] = i; break; } if (!g[now]) for (i = now-1; i ; --i) if (a[i] == -1){ g[now] = i; break; } --nowlen,nowv = a[now],now = g[now]; } for (i = 1; i <= n; ++i) if (a[i] == -1) for (j = 1; j <= m; ++j) if (b[j] != -1){ a[i] = b[j]; b[j] = -1; break; } for (i = 1; i < n; ++i) write(a[i]),putchar(i<n?' ':'\n'); return 0; }