CF568E Longest Increasing Subsequence
\(\color{#FF003F}{\texttt {CF568E Longest Increasing Subsequence}}\)
考虑LIS问题的经典 \(O(n\log n)\) 解法,\(dp_i=\max_{a_j<a_i}(dp_j)+1\), \(\operatorname{Fenwick tree}\) 优化。
回到本题,首先可以发现不重复选这个限制是没有意义的,因为重复选了对答案没有贡献。
一种 naive 的想法是对每个空缺位枚举选哪个数,dp的同时用 \(\operatorname{Fenwick tree}\) 维护数组 \(maxval\),\(maxval_i=\max_{dp_j}(a_j<=i)\)。复杂度是 \(O(n \log n + mk\log n)\)。冷静分析一下发现瓶颈在每次都要更新 \(maxval\) 数组,又发现如果只在 \(k\) 个空缺位置暴力更新复杂度是对的。
对于 \(a_i=-1\) 的位置,对 \(maxval\) 数组求前缀 \(\max\),枚举当前位选了什么数,\(dp_i=\max_{j \in S} maxval_{j-1}+1\)。
对于 \(a_i\not=-1\) 的位置,\(dp_i=maxval{a_{i-1}}+1\),其中 \(maxval\) 有两部分,分别是 \(a_i=-1\) 和 \(a_i \not=-1\)的贡献,同时维护 \(\operatorname{Fenwick tree}\) 。
考虑如何构造方案,
如果当前位不是空缺位,直接到 \(dp\) 时记录的最优转移点。
否则 \(a_i=\max_{x \in S,x<last}x\) ,并尝试向前找到一个非空缺位且满足 \(dp_j+1=dp_i (a_j<a_i)\),如果没找到,就找离 \(i\) 最近的空缺位,递归地构造。
容易证明这样一定可以构造出最优解。
对于本做法有点卡常,需要精细地实现程序。复杂度 \(O(n\log n + mk)\)
// Author -- Frame
#pragma GCC optimize(3)
#pragma GCC optimize("-Ofast","-funroll-all-loops","-ffast-math")
#pragma GCC optimize("-fno-math-errno")
#pragma GCC optimize("-funsafe-math-optimizations")
#pragma GCC optimize("-freciprocal-math")
#pragma GCC optimize("-fno-trapping-math")
#pragma GCC optimize("-fno-stack-protector")
#pragma GCC optimize("-ffinite-math-only")
#pragma GCC optimize("-ftree-vectorize")
#pragma GCC target ("avx2","sse4.2","fma")
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<iostream>
#include<map>
#define lowbit(x) ((x)&(-x))
#define Finline __inline__ __attribute__ ((always_inline))
#define DEBUG fprintf(stderr,"Running on Line %d in Function %s\n",__LINE__,__FUNCTION__)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f,Inf=0x7fffffff;
const ll INF=0x7fffffffffffffff;
const double eps=1e-10;
template <typename _Tp>_Tp gcd(const _Tp &a,const _Tp &b){return (!b)?a:gcd(b,a%b);}
template <typename _Tp>Finline _Tp abs(const _Tp &a){return a>=0?a:-a;}
template <typename _Tp>Finline _Tp max(const _Tp &a,const _Tp &b){return a<b?b:a;}
template <typename _Tp>Finline _Tp min(const _Tp &a,const _Tp &b){return a<b?a:b;}
template <typename _Tp>Finline void chmax(_Tp &a,const _Tp &b){(a<b)&&((a=b),0);}
template <typename _Tp>Finline void chmin(_Tp &a,const _Tp &b){(b<a)&&(a=b);}
template <typename _Tp>Finline bool _cmp(const _Tp &a,const _Tp &b){return abs(a-b)<=eps;}
template <typename _Tp>Finline void read(_Tp &x)
{
register char ch(getchar());
bool f(false);
while(ch<48||ch>57) f|=ch==45,ch=getchar();
x=ch&15,ch=getchar();
while(ch>=48&&ch<=57) x=(((x<<2)+x)<<1)+(ch&15),ch=getchar();
if(f) x=-x;
}
template <typename _Tp,typename... Args>Finline void read(_Tp &t,Args &...args)
{
read(t);read(args...);
}
Finline int read_str(char *s)
{
register char ch(getchar());
while(ch==' '||ch=='\r'||ch=='\n') ch=getchar();
register char *tar=s;
*tar=ch,ch=getchar();
while(ch!=' '&&ch!='\r'&&ch!='\n'&&ch!=EOF) *(++tar)=ch,ch=getchar();
return tar-s+1;
}
const int N=200005;
struct node{
int val,id;
Finline bool operator < (const node &o)const
{
return val<o.val;
}
Finline node operator + (const int &o)const
{
return (node){val+o,id};
}
}maxx[N];
struct BIT{
node c[N];
Finline void add(int x,node C){++x;for(;x<N;x+=lowbit(x))chmax(c[x],C);}
Finline node sum(int x){++x;node ans=(node){0,0};for(;x;x-=lowbit(x))chmax(ans,c[x]);return ans;}
}tr;
int a[N],t[N];
int b[N];
int dp[N];
int opt[N];
std::map<int,int> mp;
void print(int x,int last,int cur)
{
while(x)
{
if(~a[x])
{
last=a[x];
x=opt[x];
--cur;
// print(opt[x],a[x],cur-1);
}
else
{
auto it=--mp.lower_bound(last);
a[x]=it->first;
if(!--it->second) mp.erase(it);
if(dp[x]==1) return;
--cur;
last=a[x];
bool flag=false;
for(int i=1;i<x;++i)
{
if(~a[i]&&a[i]<a[x]&&dp[i]==cur)
{
x=i;
// print(i,a[x],cur-1);
flag=true;
break;
}
}
if(flag) continue;
for(int i=x-1;i>=1;--i)
{
if(!~a[i])
{
x=i;
// print(i,a[x],cur-1);
break;
}
}
}
}
}
int main()
{
int n,m;
read(n);
int pos=0;
for(int i=1;i<=n;++i)
{
read(a[i]);
if(~a[i]) t[++pos]=a[i];
}
read(m);
for(int i=1;i<=m;++i)
{
read(b[i]);
t[++pos]=b[i];
++mp[b[i]];
}
std::sort(t+1,t+pos+1);
int len=std::unique(t+1,t+pos+1)-t-1;
for(int i=1;i<=n;++i)
{
if(~a[i]) a[i]=std::lower_bound(t+1,t+len+1,a[i])-t;
}
for(int i=1;i<=m;++i)
{
b[i]=std::lower_bound(t+1,t+len+1,b[i])-t;
}
std::sort(b+1,b+m+1);
for(int i=1;i<=n;++i)
{
if(a[i]==-1)
{
for(register int j=1;j<=len;++j) chmax(maxx[j],maxx[j-1]);
for(register int j=m;j>=1;--j)
{
node tmp=(node){maxx[b[j]-1].val+1,i};
chmax(maxx[b[j]],tmp);
chmax(dp[i],tmp.val);
}
for(register int j=1;j<=len;++j) chmax(maxx[j],maxx[j-1]);
}
else
{
node qwq=tr.sum(a[i]-1);
if(qwq.val>maxx[a[i]-1].val)
{
dp[i]=qwq.val+1;
opt[i]=qwq.id;
}
else
{
dp[i]=maxx[a[i]-1].val+1;
opt[i]=maxx[a[i]-1].id;
}
tr.add(a[i],(node){dp[i],i});
chmax(maxx[a[i]],(node){dp[i],i});
}
}
int ans=0;
pos=0;
for(int i=1;i<=n;++i)
{
if(dp[i]>ans)
{
ans=dp[i];
pos=i;
}
}
for(int i=1;i<=n;++i)
{
if(~a[i])
{
a[i]=t[a[i]];
}
}
print(pos,inf,ans);
for(int i=1;i<=n;++i)
{
if(a[i]==-1)
{
a[i]=mp.begin()->first;
if(!--mp.begin()->second) mp.erase(mp.begin());
}
}
fprintf(stderr,"ans = %d\n",ans);
for(int i=1;i<=n;++i) printf("%d ",a[i]);
printf("\n");
return 0;
}
转载请注明出处
https://www.cnblogs.com/xyr2005/