ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

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。

从高位到低位dp确定k的值,状态表示为当前考虑完第i位,m已被凑出了j,此时k的最小值。观察到$j$是$2^i$的倍数,且当$\frac{j}{2^i}$在O(n)范围时才对最终答案有影响,因此总状态数可以接受,在O(nlogm)级别。

#include<bits/stdc++.h>
typedef long long i64;
const int N=2e5+7;
const i64 inf=1ll<<60;
char ib[N*30],*ip=ib;
i64 _(){
    i64 x=0;
    while(*ip<48)++ip;
    while(*ip>47)x=x*10+*ip++-48;
    return x;
}
int n,t[65][2];
i64 m,f[N],g[N];
void mins(i64&a,i64 b){if(a>b)a=b;}
int main(){
    fread(ib,1,sizeof(ib),stdin);
    n=_(),m=_();
    for(int i=1;i<=n;++i){
        i64 x=_();
        for(int j=0;j<60;++j)++t[j][x>>j&1];
    }
    n*=2;
    for(int i=1;i<=n;++i)f[i]=inf;
    for(int i=59;i>=0;--i){
        for(int j=m>>i&1;j<=n;j+=2)g[j]=f[j>>1];
        for(int j=0;j<=n;++j)f[j]=inf;
        int c1=t[i][0],c0=t[i][1];
        for(int j=m>>i&1;j<=n;j+=2)if(g[j]<inf){
            if(j>=c0)mins(f[j-c0],g[j]);
            if(j>=c1)mins(f[j-c1],g[j]|1ll<<i);
        }
    }
    printf("%lld\n",f[0]==inf?-1ll:f[0]);
    return 0;
}

 

posted on 2017-10-19 07:01  nul  阅读(265)  评论(0编辑  收藏  举报