CF891B-Gluttony【构造】

正题

题目链接:https://www.luogu.com.cn/problem/CF891B


题目大意

给出(n)个数字互不相同的一个序列(a),求它的一个排列(b),使得选出任意一个(1sim n)的下标真子集,都有(a)的对应下标和不等于(b)的对应下标和。

(1leq nleq 22,0leq a_ileq 10^9)


解题思路

首先考虑对于每个(a_i)向它对应(b_i)连边,然后如果连出来的不是一个大小为(n)的环的话显然是错的,因为一次选择相当于选择环上的一条边,那么选一个环显然是对的。

然后现在问题就变成了找一个环排列满足以上的条件,再考虑怎么找这个环排列,发现对应环上选择的连续一段那么最后肯定是头(+)而且尾(-),然后中间的不计贡献,换句话就是无法在这个环上选出一个子序列,然后(+/-)交错使得和为(0)

对于这个问题的构造就很简单了,直接选择一个递增的序列,这样每个(+)肯定有个比他更大/小的(-)与它抵消。

不过这样看上去其实是想复杂了,换种想法其实就是对于每个选出的除了最大的(a_i)都有一个更大的(b_i)对应,然后如果选择了最大的(a_i)那么这个差值需要选择另外(n-1)个才能抵上。

时间复杂度:(O(nlog n))


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=30;
int n,a[N],b[N];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),b[i]=a[i];
	sort(b+1,b+1+n);
	for(int i=1;i<=n;i++){
		if(a[i]==b[n])printf("%d ",b[1]);
		else printf("%d ",b[upper_bound(b+1,b+1+n,a[i])-b]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/QuantAsk/p/15325455.html