题意
给一个长度为n的,有K个位置空缺的序列。
然后给出m个的候选数,用于填充空缺的地方。
输出一组使得填充后最长上升子序列最长的方案。
思路
- 观察可以发现一个 的dp,尝试优化,调着调着之后发现fake掉了= =
- 瞄了一下题解,发现是这个亚子的:
- 考虑将所有候选数排倒序,然后插入每个空的地方,答案不会改变。
- 由于空只有1000个,所以答案是容易使用dp求出的。
- 注意这里要做到 ,所以使用 表示长度为i的最小结尾的方法。空的地方更新的时候两个指针扫一遍即可。
- 假如使用 的空间来存储转移前导。无法通过本题的128mb限制。
- 那我们转而存每一个确定的数的前导, 并连续赋值一段LIS中的空位置。
- 也就是假如当前位置x的前导是一个空,那么枚举前一个非空的位置y(别忘了必须满足 ),只要 之间能够填数,使得LIS长度从 增加到 即可。然后将x变成y,继续操作(这也是 dp的想法,但是要优化这个dp需要三维偏序…)
- 可以给序列前后加上正负无穷来避免繁琐的细节。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, a[N], b[N], s[N], tmp[N * 2], w[N * 2];
int m;
int js[N * 2], f[N], pre[N], c[N], from[N];
namespace test{
int f[N];
void check() {
int ans=0;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++)if(a[i]>a[j]) {
f[i]=max(f[i],f[j]+1);
}
ans=max(ans,f[i]);
}
cout<<ans - 2<<endl;
}
}
void dp() {
for(int i = 1; i <= n; i++) {
if (a[i] == -1) {
for(int j = m, zj = c[0]; j; j--) {
while(c[zj] >= b[j] && zj > 0) zj--;
if (zj == c[0]) {
c[0]++;
from[c[0]] = -1;
c[c[0]] = b[j];
} else if (b[j] < c[zj + 1]) {
from[zj + 1] = -1;
c[zj + 1] = b[j];
}
}
} else {
int z = lower_bound(c + 1, c + 1 + c[0], a[i]) - c;
if (z == c[0] + 1) c[0]++;
from[z] = i;
c[z] = a[i];
pre[i] = from[z - 1];
f[i] = z;
}
}
}
void build_solution() {
for(int now = n; now;) {
if (pre[now] != -1) {
now = pre[now];
} else {
for(int i = now - 1; i; i--) if (a[i] != -1) {
if (a[i] < a[now] && f[now] - f[i] - 1 == min(s[now - 1] - s[i], w[a[now] - 1] - w[a[i]])) {
for(int x = i + 1, zj = a[i] + 1; x < now; x++) if(a[x] == -1) {
while(js[zj] == 0 && zj + 1 < a[now]) zj++;
if (js[zj]) {
a[x] = zj;
js[zj]--; zj++;
}
}
now = i;
break;
}
}
}
}
}
int main() {
freopen("e.in", "r", stdin);
cin>>n;
a[n+2] = 1e9 + 1;
for(int i = 1; i <= n + 2; i++){
if(2 <= i && i <= n + 1) scanf("%d",&a[i]);
s[i] = s[i - 1] + (a[i] == -1);
if(a[i] != -1) tmp[++tmp[0]] = a[i];
}
n += 2;
cin>>m;
for(int i = 1; i <= m; i++){
scanf("%d", &b[i]);
tmp[++tmp[0]] = b[i];
}
sort(tmp + 1, tmp + 1 + tmp[0]);
tmp[0] = unique(tmp + 1, tmp + 1 + tmp[0]) - tmp - 1;
for(int i = 1; i <= n; i++) if (a[i] != -1) {
a[i] = lower_bound(tmp + 1, tmp + 1 + tmp[0], a[i]) - tmp;
}
for(int i = 1; i <= m; i++) {
b[i] = lower_bound(tmp + 1, tmp + 1 + tmp[0], b[i]) - tmp;
w[b[i]] = 1;
js[b[i]] ++;
}
for(int i = 1; i <= tmp[0]; i++) w[i] += w[i - 1];
sort(b + 1, b + 1 + m);
dp();
build_solution();
for(int i = 1, zj = 1; i <= n; i++) if(a[i] == - 1) {
while(js[zj] == 0) zj++;
a[i] = zj; js[zj]--;
}
for(int i = 2; i < n; i++) printf("%d ", tmp[a[i]]);
// test :: check();
}