2018.10.20【校内模拟】蛋糕(LIS/Dilworth)

传送门


解析:

按照第一位 a a a排序从大到小,求 b b b的最少的下降序列的划分数。

转换一下,求 b b b的最少下降序列个数。

根据 D i l w o r t h Dilworth Dilworth定理,由于没有相等,我们要求的就是 b b b的最长上升子序列的长度。

对于输出方案,我们在每个上升序列的位置维护一个 h e a d head head,能够补到这个位置的数就能够在最后的下降序列中出现在以 h e a d head head开头的序列中。并查集维护一下就好了。

其实排序还有一种骚操作(zxyoi瞎yy出来的),由于 a , b a,b a,b都是一个 1 − n 1-n 1n的全排列,所以我们直接用 a a a来存 b b b,同时记录一下这是输入的第几个数。

那么序自然就被排好了。。。

但是后面的复杂度仍然是 O ( n l o g n ) O(nlogn) O(nlogn)因为二分嘛。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

inline void outint(int a){
	static char ch[13];
	if(a==0)return (void)pc('0');
	while(a)ch[++ch[0]]=a-a/10*10,a/=10;
	while(ch[0])pc(ch[ch[0]--]^48);
}

cs int N=1000006;

int fa[N];
inline int getfa(int x){
	while(x^fa[x])x=fa[x]=fa[fa[x]];
	return x;
}
inline void merge(int u,int v){
	u=getfa(u);
	v=getfa(v);
	fa[max(u,v)]=min(u,v);
}
int pos[N],tot;

int len;
int a[N],head[N];
int b[N];
int id[N];
int n;
signed main(){
	n=getint();
	for(int re i=1;i<=n;++i){
		int x=getint(),
		y=getint();
		b[x]=y;
		id[x]=i;
		fa[i]=i;
	}
	for(int re i=n;i;--i){
		int c=b[i];
		if(len==0||c>a[len]){
			a[++len]=c;
			head[len]=id[i];
		}
		else{
			int k=lower_bound(a+1,a+len+1,c)-a;
			merge(head[k],id[i]);
			a[k]=c;
		}
	}
	cout<<len<<"\n";
	for(int re i=1;i<=n;++i)if(fa[i]==i)pos[i]=++tot;
	for(int re i=1;i<=n;++i)outint(pos[getfa(i)]),pc(' ');
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值