Number Sequence HDU - 5014(思维构造)

Number Sequence HDU - 5014

 There is a special number sequence which has n+1 integers. For each number in sequence, we have two rules:

● a i ∈ [0,n]
● a i ≠ a j( i ≠ j )

For sequence a and sequence b, the integrating degree t is defined as follows(“♁” denotes exclusive or):

t = (a 0 ♁ b 0) + (a 1 ♁ b 1) +···+ (a n ♁ b n)


(sequence B should also satisfy the rules described above)

Now give you a number n and the sequence a. You should calculate the maximum integrating degree t and print the sequence b.

Input
There are multiple test cases. Please process till EOF.

For each case, the first line contains an integer n(1 ≤ n ≤ 10 5), The second line contains a 0,a 1,a 2,...,a n.

Output
For each case, output two lines.The first line contains the maximum integrating degree t. The second line contains n+1 integers b 0,b 1,b 2,…,b n. There is exactly one space between b i and b i+1 (0 ≤ i ≤ n - 1). Don’t ouput any spaces after b n.
Sample Input

4
2 0 1 4 3

Sample Output

20
1 0 2 3 4

题意:

给定n,表示有0~n这n+1个数组成的序列a,要求构造一个序列b,同样是由0~n组成,要求∑ai⊕bi尽量大。

分析:

一个数对应的二进制取反后两数异或和最大,而我们发现,两两对应的数可以分成若干个区间段

Number Sequence HDU - 5014(思维构造)_第1张图片

因此只需要每次找到每段的起点和终点,向中间开始配对即可

起点和终点怎么找,终点一开始就是n,之后的每段终点就是前一段的起点-1

那么起点怎么找,找到比当前终点大的第一个2的幂次的数,减去终点再-1就是起点了

code:

#include 
using namespace std;
typedef long long ll;
const int N = 1e5+5;
const int M = 20;
int num[N];
int Map[N];
int n;
ll t[M];
void init(){
    t[0] = 1;
    for(int i = 1; i <= M; i++){
        t[i] = t[i-1] * 2;
    }
}
int main(){
    init();
    while(~scanf("%d",&n)){
        for(int i = 0; i <= n; i++){
            scanf("%d",&num[i]);
        }
        int rear = n;
        int head;
        ll ans = 0;
        while(rear >= 0){
            for(int i = 0; i < M; i++){
                if(t[i] > rear){
                    head = t[i] - rear - 1;
                    break;
                }
            }
            for(int i = 0; i < (rear - head + 1) / 2; i++){
                Map[rear - i] = head + i;
                Map[head + i] = rear - i;
            }
            if(rear == head)
                Map[rear] = head;
            rear = head - 1;
        }
        for(int i = 0; i <= n; i++){
            ans += num[i] ^ Map[num[i]];
        }
        printf("%lld\n",ans);
        for(int i = 0; i < n; i++){
            printf("%d ",Map[num[i]]);
        }
        printf("%d\n",Map[num[n]]);
    }
    return 0;
}

你可能感兴趣的:(思维技巧)