给出一个的数列,将其重新排列,使得其等差子序列的数目最小。输出一种可能的排列后的数列。
题解
构造
那天和 EdwardFrog 讨论 bzoj2124 的构造时突然有的灵感,最后发现就是这道题...
通过构造可以使得不存在长度为3的等差子序列。
考虑:如果把所有奇数放到所有偶数的左面,那么就不会出现 “奇-偶-奇” 或 “偶-奇-偶” 的情况。
对于 “奇-奇-奇” 或 “偶-偶-偶” 的情况,将所有 $a_i$ 变为 $\lfloor\frac{a_i}2\rfloor$ 不影响判断,因此将所有数除以2后重复这个过程即可。
由于一个数除以 $\log n$ 次就会变成1,因此这个过程只需要进行 $\log$ 次。
每一层都只会处理 $n$ 个数,时间复杂度 $O(n\log 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;
}