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;
}
posted @ 2020-03-29 14:02  xyr2005  阅读(241)  评论(0编辑  收藏  举报