题解 P13524 [KOI 2025 #2] 跳跃

Solution

考虑已知一个排列 \(p\) 怎么推出 \(c\),显然是维护差分标记 \(t\),对于 \(p_i,p_{i+1}\),给 \(t_{\min(p_i,p_{i+1})}\gets t_{\min(p_i,p_{i+1})}+1\) 以及 \(t_{\max(p_i,p_{i+1})}\gets t_{\max(p_i,p_{i+1})}-1\)。

显然可以从 \(c\) 简单推出 \(t\)。下面我们只讨论 \(i\in [2,n-1]\)。由于每个点只会被操作两次(到达一次,出发一次),则只可能存在 \(t_i\in \{-2,0,2\}\),且 \(\sum t_i=0\),即 \(-2\) 的个数 与 \(2\) 的个数相等。

考虑若 \(t_i=-2\),则两次操作这个点,\(i\) 都是作为终点,即 \(i\) 的左右两侧相邻的数都比 \(i\) 小;同理 \(t_i=2\) 表示两侧都比 \(i\) 大;\(t_i=0\) 表示一侧比 \(i\) 大,一侧比 \(i\) 小。

然后你会发现由于 \(c_i\) 为正,\(t_i\) 的每一个前缀和(从 \(2\) 开始)都是非负,所以第一个 \(2\) 一定在第一个 \(-2\) 之前,第二个 \(2\) 一定在第二个 \(-2\) 之前……然后就有一个很好的构造,把 \(1\) 放第一个,再放第一个 \(t_i=-2\) 的 \(i\),放第一个 \(t_i=2\) 的 \(i\),放第二个 \(t_i=-2\) 的 \(i\),以此类推,不难发现一定满足要求。

什么?你问 \(t_i=0\) 怎么办?在任意两个数 \(p_i,p_{i+1}\) 之间插 \([p_i,p_{i+1}]\) 里面(或 \([p_{i+1},p_i]\) 里面)的数就行。随便用 set 搞一下即可。

代码里还缝了一个 checker。

Code

#include<bits/stdc++.h>
using namespace std;
namespace Z3k7223{
	const int N=2e5+10;
	int n;
	int ip[N],a[N];
	int ans[N],vis[N],tot;
	int tg_chk[N];
	void check1(){
		for(int i=1;i<n;i++){
			int x=ans[i],y=ans[i+1];
			if(x>y){
				swap(x,y);
			}
			++tg_chk[x],--tg_chk[y];
		}
		sort(ans+1,ans+1+n);
		for(int i=1;i<=n;i++){
			if(ans[i]!=i){
				cerr<<"NOT A PERMUTATION!\n";
				return;
			}
		}
		for(int i=1;i<n;i++){
			tg_chk[i]+=tg_chk[i-1];
		}
		int cnt=0;
		for(int i=1;i<n;i++){
			if(tg_chk[i]!=ip[i]){
				++cnt;
			}
		}
		cerr<<cnt<<" error(s) found\n";
	}
	int tag[N];
	set<int>s;
	void ins(int x){
		if(s.empty()){
			ans[++tot]=x;
			return;
		}
		vector<int>tmp;
		if(ans[tot]>x){
			auto it=s.lower_bound(ans[tot]);
			while(it!=s.begin()){
				--it;
				if(*it<x)break;
				ans[++tot]=*it;
				tmp.push_back(*it);
			}
		}else{
			auto it=s.lower_bound(ans[tot]);
			while(it!=s.end()){
				if(*it>x)break;
				ans[++tot]=*it;
				tmp.push_back(*it);
				++it;
			}
		}
		for(int r:tmp){
			s.erase(r);
		}
		ans[++tot]=x;
	}
	void main(){
		cin>>n;
		for(int i=1;i<n;i++){
			cin>>ip[i];
		}
		for(int i=1;i<=n;i++){
			a[i]=ip[i]-ip[i-1];
			ans[i]=i;
			if(a[i]==0){
				s.insert(i);
			}
		}
		vector<int>ar,br;
		for(int i=1;i<=n;i++){
			if(a[i]==-2){
				ar.push_back(i);
			}
			if(a[i]==2){
				br.push_back(i);
			}
		}
		ans[++tot]=1;
		for(int i=0;i<ar.size();i++){
			ins(ar[i]);
			ins(br[i]);
		}
		for(int i=1;i<=n;i++){
			cout<<ans[i]<<' ';
		}
		cout<<'\n';
		check1();
	}
}
int main(){
	Z3k7223::main();
	return 0;
}
posted @ 2025-11-11 20:03  Z3k7223  阅读(32)  评论(0)    收藏  举报