F. Make Them Similar(位运算 折半 哈希)

http://codeforces.com/problemset/problem/1257/F

题意:

有一个a数组,长度最大100,现在让所有数都异或k,使得得到的数组中,所有数的二进制上的1的个数相同,求这个k。

解析:

考虑异或后的影响,列出对应方程:
在这里插入图片描述
我们要求: a 1 = a n , a 2 = a n . . . a n 1 = a n a_1=a_n,a_2=a_n...a_{n-1}=a_n ,共n-1个方程。一共30位二进制。

考虑折半,枚举前面15位二进制,将对应的式子的答案算出(n-1个答案),哈希这 n 1 n-1 个答案存到map里面。然后枚举后面15位,算出符合要求时的答案,查看是否存在。

代码:

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ULL unsigned long long

const int maxn=109;
int n;
int a[maxn];
int eqv[maxn][32];
void init(){
    rep(i,1,n-1){
        int ct=0;
        rep(j,0,29){
            bool p=0,q=0;
            if(a[i]&(1<<j))p=1;
            if(a[n]&(1<<j))q=1;
            if(p==q)eqv[i][j]=0;
            else if(p)eqv[i][j]=-2,ct++;
            else eqv[i][j]=2,ct--;
        }
        eqv[i][30]=-ct;
    }
}

unordered_map<ULL,int>Map;

int main(){
    scanf("%d",&n);
    rep(i,1,n)scanf("%d",a+i);
    init();
    // 0~14
    rep(sta,0,(1<<15)-1){
        vector<int>V(n);
        rep(i,1,n-1){
            int sum=0;
            rep(j,0,14){
                if(sta&(1<<j))sum+=eqv[i][j];
            }
            V[i]=sum;
        }
        ULL H=0;
        rep(i,1,n-1){
            H=H*23+(ULL)(V[i]);
        }
        Map[H]=sta;
    }
    //  15~29
    rep(sta,0,(1<<15)-1){
        vector<int>V(n);
        rep(i,1,n-1){
            int sum=0;
            rep(j,0,14){
                if(sta&(1<<j))sum+=eqv[i][j+15];
            }
            V[i]=eqv[i][30]-sum;
        }
        ULL H=0;
        rep(i,1,n-1){
            H=H*23+(ULL)(V[i]);
        }
        if(Map.count(H)){
            int ans=Map[H];
            rep(i,0,14){
                if(sta&(1<<i))ans|=(1<<i+15);
            }
            return 0*printf("%d\n",ans);
        }
    }
    printf("-1\n");
}

发布了723 篇原创文章 · 获赞 314 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/103163880
今日推荐