zoukankan      html  css  js  c++  java
  • CF568E Longest Increasing Subsequence

    (color{#FF003F}{ exttt {CF568E Longest Increasing Subsequence}})

    考虑LIS问题的经典 (O(nlog 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 + mklog n))。冷静分析一下发现瓶颈在每次都要更新 (maxval) 数组,又发现如果只在 (k) 个空缺位置暴力更新复杂度是对的。

    对于 (a_i=-1) 的位置,对 (maxval) 数组求前缀 (max),枚举当前位选了什么数,(dp_i=max_{j in S} maxval_{j-1}+1)

    对于 (a_i ot=-1) 的位置,(dp_i=maxval{a_{i-1}}+1),其中 (maxval) 有两部分,分别是 (a_i=-1)(a_i ot=-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(nlog 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
    ",__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=='
    '||ch=='
    ') ch=getchar();
    	register char *tar=s;
    	*tar=ch,ch=getchar();
    	while(ch!=' '&&ch!='
    '&&ch!='
    '&&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
    ",ans);
    	for(int i=1;i<=n;++i) printf("%d ",a[i]);
    	printf("
    ");
    	return 0;
    }
    
  • 相关阅读:
    第七周学习进度
    环形数组求子数组最大和
    第六周学习进度
    团队
    子数组和最大值
    第五周学习进度
    第四周学习进度
    构建之法第一篇阅读笔记
    关于Sublime text 的PHP编译环境配置的问题
    PHP基础之 数组(二)
  • 原文地址:https://www.cnblogs.com/Frame233/p/12587822.html
Copyright © 2011-2022 走看看