# HDU 5014 Number Sequence(二进制+区间贪心)

### Problem Description

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

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

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

t = (a0 ⊕ b0) + (a1 ⊕ b1) +···+ (an ⊕ bn)

(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 ≤ 105), The second line contains a0,a1,a2,…,an.

### Output

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

4
2 0 1 4 3

## Output

20
1 0 2 3 4

### 解题思路

1.题意假设给定自然数序列ai，ai ∈ [0,n] ，ai ≠ aj( i ≠ j )，求自然数序列bi，使ai与bi对应位上的每一个数进行异或运算后相加和最大
2.怎么才能使异或运算之后相加和最大，显然采用贪心策略，使每一个对应位异或后能取得最大值。所以重点在于怎么求出与那位数异或能取得最大值。
3.例如序列0 1 2 3 4 5 6 7 8 9 10转化成二进制00000000 00000001 00000010 00000011 00000100 00000101 00000110 00000111 00001000 00001001 00001010，不难发现当转化为二进制时每一位互补时能取得最大值，如00001010和00000101,00001001和00000110,00001000和00000111，并且可以发现是在一个区间内两两对应，因为当5(00000101)和10(00001010)互补时，5+1(00000110)和10-1(00001001)也互补。
4.所以问题转化成怎么求互补数的问题，这里需要二进制的知识，首先找出第一个比给定数字n大的数，这个数必须是2的倍数，所以比10大的且是2的倍数的数是16(00010000)，然后16-1(00001111)，再将n按位取反~n(11110101)后进行按位与运算&，得到与n(10)互补的数c(5)(00000101)，所以这样一个区间就解决了，剩下的只需要重复此过程就可以

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<memory.h>
#include<algorithm>
using namespace std;
const int N=100005;
int a[N],b[N];
long long int sum;
void f(int n){
if(n<=0){
return;
}
int k=0;
while((1<<k)<=n)k++;
//求比n大的数，这个数是2的倍数，10->16
//1<<k，就是2^k
int cur=1<<k;
int c=~n&(cur-1);//求与n互补的数
for(int i=n,j=c;i>j;j++,i--){
b[i]=j;
b[j]=i;
sum+=(i^j)*2;
}
if(cur!=0){//进行下一个区间
f(c-1);
}
}
int main(){
int n;
while(scanf("%d",&n)!=EOF){
sum=0;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=0;i<=n;i++){
scanf("%d",&a[i]);
}
f(n);
printf("%lld\n",sum);
for(int i=0;i<=n;i++){
printf("%d%c",b[a[i]],(i==n)?'\n':' ');
}
}
return 0;
}


• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120