卡常垃圾!!!
题目链接
如果没有空位,那么是一个经典的求LIS的问题,直接用树状数组维护dp[i]表示以数字i为结尾的LIS即可。
注意到比较不好做的地方在于m个数每个只能用一次,如果多记一维目前用到哪效率会炸。但既然要求严格上升,那么重复用一个数肯定没有用,所以完全可以忽略这个限制。于是遇到一个空位,直接用
O
(
m
)
O(m)
O(m)对目前所有dp值进行更新即可(树状数组因为是前缀max可做到
O
(
m
)
O(m)
O(m)重构)。
记录方案时,如果要记录每个状态的转移点空间会炸,考虑先忽略空位,然后在LIS的相邻两个数之间,尽量按顺序填入这些空位,其它空位乱填即可,效率
O
(
m
k
+
n
l
o
g
n
)
O(mk+nlogn)
O(mk+nlogn)。
代码:(毒瘤题卡常卡到怀疑人生)
#include<bits/stdc++.h>
using namespace std;
int R(){
int s=0; bool p=0; char c=getchar();
while(!isdigit(c)){
if(c=='-') p=1; c=getchar();
}
while(isdigit(c)) s=(s<<3)+(s<<1)+(c-48),c=getchar();
if(p) s=-s; return s;
}
const int N=2e5+5;
int n,m,a[N],b[N],c[N],q[N],t;
#define st first
#define nd second
#define mp make_pair
pair<int,int> dp[N],mx[N],pt[N],tp[N];
void upd(pair<int,int> u,int x){
for(;x<=t;x+=(x&(-x))) if(u.st>mx[x].st) mx[x]=u;
}
pair<int,int> qry(int x){
pair<int,int> u=mp(0,0);
for(;x;x-=(x&(-x))) if(mx[x].st>u.st) u=mx[x];
return u;
}
int ps[N],tt;
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
a[i]=R();
if(~a[i]) q[++t]=a[i];
}
cin>>m;
for(int i=1;i<=m;i++) b[i]=R(),q[++t]=b[i];
sort(q+1,q+t+1); t=unique(q+1,q+t+1)-q-1;
for(int i=1;i<=m;i++) b[i]=lower_bound(q+1,q+t+1,b[i])-q,c[b[i]]++;
sort(b+1,b+m+1); m=unique(b+1,b+m+1)-b-1;
for(int i=1;i<=n;i++){
if(~a[i]){
a[i]=lower_bound(q+1,q+t+1,a[i])-q;
pair<int,int> u=qry(a[i]-1); pt[i]=u;
u.st++; u.nd=i;
if(u.st>dp[a[i]].st) dp[a[i]]=u,upd(u,a[i]);
}
else{
for(register int i=1;i<=t;i++){
tp[i]=dp[i];
if(tp[i-1].st>tp[i].st) tp[i]=tp[i-1];
}
for(register int i=1;i<=m;i++){
pair<int,int> v=tp[b[i]-1]; v.st++;
if(v.st>dp[b[i]].st) dp[b[i]]=v;
}
for(register int i=1;i<=t;i++){
mx[i]=dp[i];
if(mx[i-1].st>mx[i].st) mx[i]=mx[i-1];
}
}
}
pair<int,int> u=qry(t);
while(u.st){
ps[++tt]=u.nd;
u=pt[u.nd];
}
reverse(ps+1,ps+tt+1); ps[tt+1]=n+1; a[n+1]=t+1;
for(int i=0,j=1;i<=tt;i++){
for(int k=ps[i]+1;k<ps[i+1];k++) if(a[k]==-1){
while(j<=a[ps[i]]) j++;
while(!c[j] && j+1<a[ps[i+1]]) j++;
if(c[j] && j<a[ps[i+1]]){
a[k]=j; c[j]--; j++;
}
}
}
for(int i=1,j=1;i<=n;i++) if(a[i]==-1){
while(!c[j]) j++; a[i]=j; c[j]--;
}
for(int i=1;i<=n;i++) printf("%d ",q[a[i]]);
return 0;
}
CF体验极差,此题卡常极其恶心,我卡了一天自闭了。
改了个地方以为常数能除2,调了几百年发现假了,心态炸裂。
它到底做错了什么???难道有任何地方有可能优化吗??????
关键是,为什么,没有人,和我一样,TLE在12???
垃圾题真的毁我青春,我不管了。
我对CF有阴影了,Atcoder多好啊(目前没wa过 虽然只写了4题 )。