• 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/

  • 相关阅读:
    《相约星期二》--[美]米奇·阿尔博姆
    《把信送给加西亚》--[美]阿尔伯特·哈伯德
    《少有人走的路:心智成熟的旅程》--[美]M·斯科特·派克
    《穷爸爸和富爸爸》--[美]罗伯特·清崎,[美]莱希
    Error This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. T
    C#轻量级高性能日志组件EasyLogger
    我们为何要跳槽
    Grid++Report报表工具C/S实战篇(五)
    .NET 开源Protobuf-net从入门到精通
    怎样防止ddos攻击
  • 原文地址:https://www.cnblogs.com/xyr2005/p/12587822.html
Copyright © 2020-2023  润新知