HDU - 5014 Number Sequence(贪心+位运算)

Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u

[]   [Go Back]   [Status]  

Description

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
 

题目大意:
有一个a集合满足
● a i ∈ [0,n] 
● a i ≠ a j( i ≠ j ) 

同样的b也满足该规则,
现在问你是否存在一个序列b,使得t最大

t = (a 0 � b 0) + (a 1 � b 1) +・・・+ (a n � b n)

n(1 ≤ n ≤ 10 5)


解析:贪心题,但是比赛时候我用的是回溯求解该题,一直超时。后来想想我太笨了如果用回溯的话复杂度为O(10^10),太大了。

其实弄清楚了这题的思路敲起来还是蛮简单的,每一个数的最大的异或是和他互补的数。10101^01010最大,如果全部都取最大,那么最后的t肯定最大。

那么一个数的互补怎么求呢? 就是这个数 异或上 与该数二进制位数相同,且都为1的数

       1010

xor  1111

       0101

弄清楚这个就好办了。求出所有数的互补,把它存入一个数组中,最后按照输入时的顺序输出该数组,就好了。

注意:Hdu有个比较坑的地方,就是不能开成long long 所以应该把t 声明为__int64才能过,坑爹啊。


#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
typedef __int64 LL;
const int MAX = 100005;
int a[MAX],ans[MAX],vis[MAX];

int main() {
	int n;
	while(scanf("%d",&n)!=EOF) {
		for(int i = 0;i <= n;++i)
			scanf("%d",&a[i]);
		memset(vis,0,sizeof(vis));
		memset(ans,0,sizeof(ans));
		for(int i = n;i > 0;--i) {
			if(vis[i])
				continue;
			int d = log2(i)+1;
			int temp = ((1 << d) - 1)  ^ i;
			ans[i] = temp;
			ans[temp] = i;
			vis[temp] = vis[i] = 1;
		}
		LL sum = 0;
		for(int i = 0;i <= n;++i)
			sum += (LL)(i ^ ans[i]);
		printf("%I64d\n",sum);
		for(int i = 0;i < n;++i)
			printf("%d ",ans[a[i]]);
		printf("%d\n",ans[a[n]]);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值