怎么还有卡空间题。。。
设原来给定的序列为
a
a
a,能填的序列为
b
b
b。
考虑经典LIS的
O
(
n
log
n
)
\mathcal O(n\log n)
O(nlogn)做法,我们维护了一个数组
F
[
i
]
F[i]
F[i]表示长度为
i
i
i的上升子序列的最小结尾,每次可以二分。我们可以魔改一下这个做法,对于
a
i
≠
−
1
a_i \neq-1
ai=−1的位置仍然二分,对于
a
i
=
−
1
a_i=-1
ai=−1的位置我们重新计算整个数组,如果预先对
b
b
b排序就可以two pointer了。这样是
O
(
n
log
n
+
(
n
+
m
)
k
)
\mathcal O(n\log n+(n+m)k)
O(nlogn+(n+m)k)的。
不过我们现在要输出方案,一般的想法是对每个元素记录转移到它的位置,但是空间限制不容许我们对
a
i
=
−
1
a_i=-1
ai=−1的位置这么做。我们可以只记录
a
i
≠
−
1
a_i\neq -1
ai=−1的位置的前驱,倒序输出的时候我们只跳到
≠
−
1
\neq -1
=−1的位置,如果它的前驱仍然满足
≠
−
1
\neq -1
=−1就直接跳,否则我们尝试跳过前面
=
−
1
=-1
=−1的位置,即直接枚举前面第一个
≠
−
1
\neq -1
=−1的位置,预处理一些信息就可以
O
(
1
)
\mathcal O(1)
O(1)判定了。
总时间复杂度仍然是
O
(
n
log
n
+
(
n
+
m
)
k
)
\mathcal O(n\log n+(n+m)k)
O(nlogn+(n+m)k)。
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define last last2
#define FR first
#define SE second
using namespace std;
typedef pair<int,int> pr;
int a[100005],b[100005];
pr f[100005],g[100005],q[100005];
int pre[100005];
void dp(int n,int m) {
memset(f,0x3f,sizeof(f));
f[0]=pr(0,0);
int cnt=0,last=0;
for(int i=1;i<=n+1;i++) {
pre[i]=last;
if (a[i]!=-1) {
if (a[i]>f[cnt].FR) {
f[++cnt]=pr(a[i],i);
g[i]=pr(cnt,f[cnt-1].SE);
}
else {
int t=lower_bound(f+1,f+cnt+1,pr(a[i],0))-f;
g[i]=pr(t,f[t-1].SE);
f[t]=pr(a[i],i);
}
}
else {
int r=1,sz=0;
for(int j=1;j<=cnt+1;j++) {
while (r<=m&&b[r]<=f[j-1].FR) r++;
if (r>m) break;
if (b[r]<f[j].FR) q[++sz]=pr(j,b[r]);
}
for(int j=1;j<=sz;j++) f[q[j].FR]=pr(q[j].SE,i);
if (f[cnt+1].FR<inf) cnt++;
last=i;
}
}
}
int ans[100005],d[100005];
int c[100005];
bool vis[100005];
void output(int n,int m) {
int sz=0;
for(int i=1;i<=m;i++)
if (i==1||b[i]!=b[i-1]) c[++sz]=b[i];
int sz2=sz;
for(int i=2;i<=m;i++)
if (b[i]==b[i-1]) c[++sz2]=b[i];
for(int i=0;i<=n;i++)
if (a[i]!=-1) d[i]=upper_bound(c+1,c+sz+1,a[i])-c;
int x=n+1;
while (x)
if (a[g[x].SE]!=-1) x=g[x].SE;
else {
int s=0,t=lower_bound(c+1,c+sz+1,a[x])-c-1;
for(int i=x-1;i>=0;i--)
if (a[i]!=-1) {
if (a[i]<a[x]&&g[i].FR+min(s,t-d[i]+1)+1==g[x].FR) {
int v=min(s,t-d[i]+1);
x=pre[x];
for(int j=1;j<=v;j++) {
ans[x]=c[t-j+1];
vis[t-j+1]=1;
x=pre[x];
}
x=i;
break;
}
}
else s++;
}
int r=1;
for(int i=1;i<=n;i++)
if (a[i]!=-1) ans[i]=a[i];
else if (!ans[i]) {
while (r<=m&&vis[r]) r++;
vis[r]=1;
ans[i]=c[r];
}
}
int main() {
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
a[n+1]=1e9+1;
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%d",&b[i]);
sort(b+1,b+m+1);
dp(n,m);
output(n,m);
for(int i=1;i<=n;i++) printf("%d ",ans[i]);
printf("\n");
return 0;
}