Description
小Q发明了一个新的加密算法,对于一个长度为n的非负整数序列a_1,a_2,...,a_n,他会随机选择一个非负整数k,
将每个数都异或上k得到b_1,b_2,...,b_n,即b_i=a_i xor k。不幸的是,健忘的小Q睡了一觉之后就把密钥k忘得
一干二净了,不过他隐约记得a_1+a_2+...+a_n的值为m,你能帮他找到一个可行的密钥吗
Input
第一行包含两个整数n,m(1<=n<=100000,0<=m<2^{60}),分别表示序列的长度以及加密前所有数的和。
第二行包含n个整数b_1,b_2,...,b_n(0<=b_i<2^{60}),表示加密后的序列。
Output
输出一个非负整数k,若无解输出-1,若有多组解,输出最小的k。
Sample Input
3 5
1 2 3
1 2 3
Sample Output
1
c[i]代表m的二进制第i位是否为1,d[i]代表数组b中二进制第i位有几个1,f[i][j]代表到第i个数,还剩j*(2^i)时的最小值。
//
// main.cpp
// bzoj5043
//
// Created by zc on 2017/10/16.
// Copyright © 2017年 zc. All rights reserved.
//
#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define ll long long
#define min(a,b) ((a)<(b))?(a):(b)
using namespace std;
const ll INF=1ll<<60;
const int N=2e5+10;
ll m, t, f[2][N];
int n, d[60], c[60] ,k;
int main(int argc, const char * argv[]) {
scanf("%d%lld",&n,&m);
for(int i=0;i<60;i++) c[i]=(m>>i)&1;
memset(d,0,sizeof(d));
for(int i=0;i<n;i++)
{
scanf("%lld",&t);
for(int j=0;j<60;j++) d[j]+=(t>>j)&1;
}
memset(f[0],127,sizeof(f[0]));
f[0][0]=0;
for(int i=59;i>=0;i--)
{
memset(f[i&1],127,sizeof(f[i&1]));
for(int j=0;j<N;j++)
{
if(f[1-(i&1)][j]>=INF) continue;
k=j*2+c[i]-d[i];//第i位取0时
if(k>=0&&k<N) f[i&1][k]=min(f[i&1][k],f[1-(i&1)][j]);
k=j*2+c[i]-n+d[i];//第i位取1时
if(k>=0&&k<N) f[i&1][k]=min(f[i&1][k],f[1-(i&1)][j]+(1ll<<i));
}
}
if(f[0][0]>=INF) f[0][0]=-1;
printf("%lld\n",f[0][0]);
}