hdu 5014 Number Sequence 2014 ACM/ICPC Asia Regional Xi'an Online 数论

题目链接:hdu 5014

        给出一个从0到n的全排列数组a,求一个对应的数组使得,a[i]^b[i]的总和最大,输出总和并输出b数组

        

        要使得异或值最大,就要让每个数的1尽量加进计数中,因此对于每个数a,要找到匹配数b使得两者的异或值为两者的和

        从最高位n开始向0找每个数的匹配数,对于数a,若该数尚未匹配,则找数b使得a+b的值为2^x-1,(x为a的二进制位数),最大和即为0~n的总和的两倍

/******************************************************
 * File Name:   1008.cpp
 * Author:      kojimai
 * Creater Time:2014年09月14日 星期日 13时25分56秒
******************************************************/

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define FFF 100005
int match[FFF];
int val[FFF];
int a[FFF];
void init()
{
	val[1]=1;
	for(int i = 2;i <= 17; i++)
	{
		val[i]=(val[i-1]+1)*2-1;
	}
	return;
}
int qfind(int x)
{
	int l=1,r=17,mid;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(val[mid]>x)
		{
			r=mid-1;
		}
		else
			l=mid+1;
	}
	return l;
}
int main()
{
	int n;
	init();
	while(~scanf("%d",&n))
	{
		memset(match,-1,sizeof(match));
		long long all=0;
		for(int i=0;i<=n;i++)
		{
			scanf("%d",&a[i]);
			all+=a[i];
		}
		all*=2;
		int t=qfind(n);
		for(int i=n;i>=0;i--)
		{
			if(match[i]==-1)
			{
				if(i==0)
				{
					match[0]=0;
					break;
				}
				while(i<=val[t-1])
					t--;
				match[i]=val[t]-i;
				match[val[t]-i]=i;
			}
		}
		cout<<all<<endl;
		//long long debug=0;
		for(int i=0;i<=n;i++)
		{
			//debug+=match[a[i]];
			if(i==0)
				printf("%d",match[a[i]]);
			else
				printf(" %d",match[a[i]]);
		}
		cout<<endl;
		//cout<<"debug = "<<debug<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值