题目大意:给定数列以及数列值的范围,求该范围内另一个数列,使得两个数列对应位的异或和最大。
解题思路:就是对于每一个数要尽量避免自己的二进制位上的1被异或掉,也尽量要让0异或为1。推一下就可以发现规律的,先贴上队友的code,后边再补上详细的分析和自己的code。今天晚上的心情一直滴落中,太可惜了!其它详见code。
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=5014
code:
#include <cstdio>
#include <cstring>
#define maxn 100011
int a[maxn],b[maxn];
long long ans;
int main(){
//freopen("input.txt", "r", stdin);
int n;
while(~scanf("%d",&n)){
ans=0;
memset(b,-1,sizeof b);
for(int i=0;i<=n;++i){
scanf("%d",a+i);
ans+=a[i];
}
ans<<=1;
printf("%I64d\n",ans);
for(int i=n;i>=0;--i)
if(b[i] == -1){
int t=i,j=1,res=0;
while(t){
if(t&1);
else res|=j;
j<<=1;
t>>=1;
}
b[i] = res;
b[res] = i;
}
for(int i=0;i<n;++i)
printf("%d ",b[a[i]]);
printf("%d\n",b[a[n]]);
}
return 0;
}
这里补一个我写的code,时间不能算是最快,但算是很好理解的形式了,注释很清楚的,详见code。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 1e5+10;
int n,a[MAXN],b[MAXN];
int vis[MAXN];
int main(){
//freopen("input.txt","r",stdin);
while(~scanf("%d",&n)){
memset(vis,0,sizeof(vis));
for(int i=n;i>=0;--i){ //逆序遍历,保证最大最优选取
if(!vis[i]){
int t=1;
while(t<=i) t<<=1; //找到比i大一位的二进制数,即2的指数
vis[i]=vis[i^(t-1)]=1;//t-1肯定是与i二进制位数相同的全1,那么异或就能找到最优匹配
b[i]=i^(t-1);//相互标记
b[i^(t-1)]=i;
}
}
printf("%I64d\n",(1LL+n)*n); //可以推出最大值为各个数的2倍和,则求和即可
for(int i=0;i<=n;++i){ //对应的输出
scanf("%d",&a[i]);
if(i!=n) printf("%d ",b[a[i]]);
else printf("%d\n",b[a[n]]);
}
}
return 0;
}

探讨了给定数列及值范围下,如何寻找另一数列使两数列对应位异或和最大。提供了两种实现思路及代码示例。
6389

被折叠的 条评论
为什么被折叠?



