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尽量大。
分析:
一个数对应的二进制取反后两数异或和最大,而我们发现,两两对应的数可以分成若干个区间段
因此只需要每次找到每段的起点和终点,向中间开始配对即可
起点和终点怎么找,终点一开始就是n,之后的每段终点就是前一段的起点-1
那么起点怎么找,找到比当前终点大的第一个2的幂次的数,减去终点再-1就是起点了
code:
#include <bits/stdc++.h>
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;
}