【uoj#143】[UER #5]万圣节的数列 构造

题目描述

给出一个的数列,将其重新排列,使得其等差子序列的数目最小。输出一种可能的排列后的数列。


题解

构造

那天和 EdwardFrog 讨论 bzoj2124 的构造时突然有的灵感,最后发现就是这道题...

通过构造可以使得不存在长度为3的等差子序列。

考虑:如果把所有奇数放到所有偶数的左面,那么就不会出现 “奇-偶-奇” 或 “偶-奇-偶” 的情况。

对于 “奇-奇-奇” 或 “偶-偶-偶” 的情况,将所有 $a_i$ 变为 $lfloorfrac{a_i}2 floor$ 不影响判断,因此将所有数除以2后重复这个过程即可。

由于一个数除以 $log n$ 次就会变成1,因此这个过程只需要进行 $log$ 次。

每一层都只会处理 $n$ 个数,时间复杂度 $O(nlog n)$ 。

#include <cstdio>
int a[510] , p[510] , t[510];
void solve(int l , int r , int x)
{
	if(!x || l >= r) return;
	int i , b = l , e = r;
	for(i = l ; i <= r ; i ++ )
	{
		if(a[p[i]] & 1) t[b ++ ] = p[i];
		else t[e -- ] = p[i];
	}
	for(i = l ; i <= r ; i ++ ) a[p[i]] >>= 1 , p[i] = t[i];
	solve(l , e , x - 1) , solve(b , r , x - 1);
}
int main()
{
	int n , i;
	scanf("%d" , &n);
	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , p[i] = i;
	solve(1 , n , 30);
	for(i = 1 ; i <= n ; i ++ ) printf("%d " , p[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/GXZlegend/p/8677219.html