CF1214E题解

Petya and Construction Set

题目传送门

题解

一个构造题,结论挺容易猜的。观察到关键信息:\(d_i\le n\)。所以我们先把所有奇数编号的点按对应的 \(d\) 从大到小组成一条链,然后依次考虑偶数号点应该接在链上的哪个点后,容易知道这个点为链上的第 \(i+d-1\) 个。特殊的,如果接在了最后一个点后面,我们就更新链的长度。

我可以告诉你,这是对的,证明如下(感觉比另一篇的证明简单些):

我们用归纳法。

  • 第一个点一定能找到对应的位置,这是因为 \(d_i\le n\)

  • 假设第 \(i-1\) 个点找到了对应位置,那么第 \(i\) 个点也可以找到对应位置,这是因为第 \(i-1\) 个点找到了对应位置就意味着从第 \(i-1\) 个点往后,至少存在 \(d_{i-1}\) 个点,而 \(d_i\le d_{i-1}\),所以我们要找 \(i\) 后第 \(d_i-1\) 个点一定存在。

  • 可推广至 \(n\)

代码已经短到一种境界了:

#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int rd() {
	int s=0,m=0;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-')m=1;ch=getchar();}
	while( isdigit(ch)) s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
	return m?-s:s;
}
int n,l[200005],cnt;
struct QWQ {int id,d;} a[200005];
bool cmp(QWQ a1,QWQ a2) {return a1.d>a2.d;}
signed main() {
	cin>>n;
	for(int i=1;i<=n;i++)
		a[i]={i,rd()};
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++)
		l[++cnt]=a[i].id*2-1;
	for(int i=1;i<n;i++)
		printf("%lld %lld\n",l[i],l[i+1]);
	for(int i=1;i<=n;i++) {
		int j=i+a[i].d-1;
		printf("%lld %lld\n",l[j],a[i].id*2);
		if(j==cnt) 
			l[++cnt]=a[i].id*2;
	}
	return 0;
}

posted @ 2024-01-19 15:27  operator-  阅读(26)  评论(0)    收藏  举报