P7726 天体探测仪(Astral Detector)

P7726 天体探测仪(Astral Detector)

存在一个排列1~n,给出它的每个长度的所有子区间的最小值,请求出一种原排列

\(1\leq n\leq 800\)

可能是因为这种题指向很明显,对于这类区间\(\tt min/max\)的问题首先得想到笛卡尔树

想想我们建笛卡尔树的方法:每次查询区间最小值,将其作为根,再将左右区间递归下去

这样给了我们启示:对于每个节点,我们可以通过它代表的区间大小和左右子树大小以及节点编号还原出一颗满足条件的笛卡尔树,进而还原原序列

首先,笛卡尔树中编号\(n\)代表的原区间大小就是\(\tt min=n\)的最长的一个区间长度\(A\)

求出\(\tt min=n\)的区间个数\(B\),设左子树长度\(L\),右子树\(R\)

\[\begin{cases} (L+1)(R+1)=B\\ L+R-1=A \end{cases} \]

解出左右子树大小后从后往前对应连边即可

时间复杂度\(O(n^2)\)

#include<bits/stdc++.h>
using namespace std;
# define ll long long
# define read read1<ll>()
# define Type template<typename T>
Type T read1(){
	T t=0;
	char k;
	bool vis=0;
	do (k=getchar())=='-'&&(vis=1);while('0'>k||k>'9');
	while('0'<=k&&k<='9')t=(t<<3)+(t<<1)+(k^'0'),k=getchar();
	return vis?-t:t;
}
# define fre(k) freopen(k".in","r",stdin);freopen(k".out","w",stdout)
int s,a[805][805],Len[805],Sum[805],L[805],R[805];
pair<int,int>f[805];
stack<int>sta[805];
void print(int x){
	if(!x)return;
	print(L[x]);
	printf("%d ",x);
	print(R[x]);
}
int main(){
	s=read;
	for(int i=1;i<=s;++i)
		for(int j=1;i+j<=s+1;++j)
			++a[i][read];
	for(int i=1;i<=s;++i)
		for(int j=1;i+j<=s+1;++j)
			Len[j]=a[i][j]?i:Len[j],Sum[j]+=a[i][j];
	for(int i=1;i<=s;++i){
		double w=sqrt(pow(Len[i]+1,2)-4*Sum[i]);
		int x=round((Len[i]+1+w)/2),y=round((Len[i]+1-w)/2);
		f[i]=make_pair(x-1,y-1);
	}for(int i=s;i;--i){
		if(f[i].first)L[i]=sta[f[i].first].top(),sta[f[i].first].pop();
		if(f[i].second)R[i]=sta[f[i].second].top(),sta[f[i].second].pop();
		sta[Len[i]].push(i);
	}
	print(1);
	return 0;
}
posted @ 2021-07-16 09:41  ファイナル  阅读(169)  评论(0编辑  收藏  举报