Codeforces Round #827 (Div. 4)

G. Orray

https://codeforces.com/contest/1742/problem/G

2 seconds / 256 megabytes

standard input / standard output

Problem

You are given an array a consisting of n nonnegative integers.

Let's define the prefix OR array b as the array bi=a1 OR a2 OR  OR ai, where OR represents the bitwise OR operation. In other words, the array b is formed by computing the OR of every prefix of a.

You are asked to rearrange the elements of the array a in such a way that its prefix OR array is lexicographically maximum.

An array x is lexicographically greater than an array y if in the first position where x and y differ, xi>yi.

Input

The first line of the input contains a single integer 1t100 — the number of test cases. The description of test cases follows.

The first line of each test case contains a single integer n (1n2105) — the length of the array a.

The second line of each test case contains n nonnegative integers a1,,an (0ai109).

It is guaranteed that the sum of n over all test cases does not exceed 2105.

Output

For each test case print n integers — any rearrangement of the array a that obtains the lexicographically maximum prefix OR array.

Example

input:

5
4
1 2 4 8
7
5 1 2 3 4 5 5
2
1 101
6
2 3 4 2 3 4
8
1 4 2 3 4 5 7 1

output:

8 4 2 1
5 2 1 3 4 5 5
101 1
4 3 2 2 3 4
7 1 4 2 3 4 5 1

题解

先考虑暴力做法,每一次取数遍历整个数列,找到与前缀或的上一位做 OR 操作的结果最大的数,从原序列中删除并加入答案序列(代码实现为直接输出该数并打上标记),代码如下:

int pre = 0, tmp = 0;
for (int i = 0; i < n; i++)
{
    int idx = -1;
    for (int j = 0; j < n; j++)
    {
        if (!vis[j] && tmp < (pre | a[j]))
        {
            tmp = (pre | a[j]);
            idx = j;
        }
    }
    pre = tmp;
    cout << a[idx] << ' ';
    vis[idx] = true;
}

用这个代码测样例就会发现问题:找到并输出了几个数之后,得到了前几个数的前缀或,再和数列中剩下的数取或得到的结果都是一样的,即 idx 一直为初值 1,作为数组下标然后产生异常。

为了解决这个问题,我们当然可以把第 7 行的 < 改成 ,然后喜提一个 O(n2)TLE 代码。但同时这也是个突破口,提示着正确的解题方式。

注意整数 ai 最大为 109,那么 ai 的二进制表示最多有 log2109+1=30 位,那么意味着,我们最多找到 30 个顺序对结果有影响的数,其他的数的顺序不影响结果。因为最多通过 30 次或运算,我们就能把前缀或中能变成 1 的位都变成 1,后面的数已经没有更多的 1 位了。

那我们在一次迭代中,如果发现 idx 没有更新,就可以停止迭代,然后按随意顺序输出剩下的数,即可得到答案了。这种方式的复杂度为 O(n),完全可以接受。

代码

易错点:| 运算符的优先级比 <> 低,因此tmp < (pre | a[j])的括号一定不要忘了,否则会产生错误结果。

#include <bits/stdc++.h>

using namespace std;

void solve()
{
    int n;
    cin >> n;
    vector<int> a(n);
    vector<bool> vis(n);
    for (int i = 0; i < n; i++)
        cin >> a[i];
    int pre = 0, tmp = 0;
    for (int i = 0; i < n; i++)
    {
        int idx = -1;
        for (int j = 0; j < n; j++)
        {
            if (!vis[j] && tmp < (pre | a[j]))
            {
                tmp = (pre | a[j]);
                idx = j;
            }
        }
        if (idx == -1)
            break;
        pre = tmp;
        cout << a[idx] << ' ';
        vis[idx] = true;
    }
    for (int i = 0; i < n; i++)
        if (!vis[i])
            cout << a[i] << ' ';
    cout << endl;
}

int main()
{
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}