CF568E. Longest Increasing Subsequence

卡常垃圾!!!
题目链接
如果没有空位,那么是一个经典的求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题 )。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值