codeforces 1257F (折半 + 技巧 (Meet-in-the-middle))

F. Make Them Similar

Let’s call two numbers similar if their binary representations contain the same number of digits equal to 1. For example:

2 and 4 are similar (binary representations are 10 and 100);
1337 and 4213 are similar (binary representations are 10100111001 and 1000001110101);
3 and 2 are not similar (binary representations are 11 and 10);
42 and 13 are similar (binary representations are 101010 and 1101).
You are given an array of 𝑛 integers 𝑎1, 𝑎2, …, 𝑎𝑛. You may choose a non-negative integer 𝑥, and then get another array of 𝑛 integers 𝑏1, 𝑏2, …, 𝑏𝑛, where 𝑏𝑖=𝑎𝑖⊕𝑥 (⊕ denotes bitwise XOR).

Is it possible to obtain an array 𝑏 where all numbers are similar to each other?

Input
The first line contains one integer 𝑛 (2≤𝑛≤100).

The second line contains 𝑛 integers 𝑎1, 𝑎2, …, 𝑎𝑛 (0≤𝑎𝑖≤230−1).

Output
If it is impossible to choose 𝑥 so that all elements in the resulting array are similar to each other, print one integer −1.

Otherwise, print any non-negative integer not exceeding 230−1 that can be used as 𝑥 so that all elements in the resulting array are similar.

Examples

input

2
7 2

output

1

input

4
3 17 6 0

output

5

input

3
1 2 3

output

-1

input

3
43 12 12

output

1073709057

题意: 给一个100大小的数组,求一个 x ,有 b i = a i b_i = a_i bi=ai ^ x x x,使得最后 b 数组的每个数二进制 1 的个数相同。

Analyse: 写这个题解,完全是为了记录一下这个技巧。很巧妙。

假设答案是 x, C [ i ] [ 0 ] C[i][0] C[i][0] 表示 a i a_i ai ^ x x x低15位 二进制1的个数, C [ i ] [ 1 ] C[i][1] C[i][1] 表示 a i a_i ai ^ x x x高15位 二进制1的个数

由题意,有 C [ i ] [ 0 ] + C [ i ] [ 1 ] = = C [ i + 1 ] [ 0 ] + C [ i + 1 ] [ 1 ] , f o r ( i    i n    r a n g e [ 1 , n   −   1 ] ) C[i][0] + C[i][1] == C[i + 1][0] + C[i + 1][1], for(i\ \ in\ \ range[1,n\ -\ 1]) C[i][0]+C[i][1]==C[i+1][0]+C[i+1][1],for(i  in  range[1,n  1])

那么变化一下等式,其实就是 C [ i ] [ 0 ] − C [ i + 1 ] [ 0 ] = = C [ i + 1 ] [ 1 ] − C [ i ] [ 1 ] , f o r ( i    i n    r a n g e [ 1 , n   −   1 ] ) C[i][0] - C[i + 1][0] == C[i + 1][1] - C[i][1], for(i\ \ in\ \ range[1,n\ -\ 1]) C[i][0]C[i+1][0]==C[i+1][1]C[i][1],for(i  in  range[1,n  1])

那么这样子,低15位高15位就分开了

枚举低15位的数 y,高15位的数 z,分别产生两个数组,即等式两边。若两数组完全相同,那么 a n s = y   ∣   ( z < < 15 ) ans = y\ |\ (z << 15) ans=y  (z<<15)

低15位求二进制1的个数 = _ _ b u i l t i n _ p o p c o u n t ( \_\_builtin\_popcount( __builtin_popcount( ( a i (a_i (ai ^ x ) x) x) % \% % ( 1 < < 15 ) ) (1 << 15)) (1<<15))

高15位求二进制1的个数 = _ _ b u i l t i n _ p o p c o u n t ( \_\_builtin\_popcount( __builtin_popcount( ( ( a i > > 15 ) ((a_i >> 15) ((ai>>15) ^ x ) ) x)) x))

其中:int __builtin_popcount(int a)函数 // 返回一个数二进制1的个数

Code:

#include<bits/stdc++.h>
#define debug(x) cerr << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a, b) memset((a),b,sizeof(a))
#define rep(i, a, b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#define fi first
#define se second
#define ptch putchar
#define CLR(a) while(!(a).empty()) a.pop()

using namespace std;

#ifndef ONLINE_JUDGE
clock_t prostart = clock();
#endif

int a[110],n,ans = -1;
vector<int> v;
map<vector<int>,int> mp;

void dfs1(int i,int x) {
    if(i == 15) {
        v.clear();
        for(int i = 1;i < n;++ i) {
            v.pb(__builtin_popcount((a[i + 1] ^ x) % (1 << 15)) - __builtin_popcount((a[i] ^ x) % (1 << 15)));
        }
        mp[v] = x;
        return ;
    }
    dfs1(i + 1,x);
    dfs1(i + 1,x | (1 << i));
}

void dfs2(int i,int x) {
    if(i == 15) {
        v.clear();
        for(int i = 1;i < n;++ i) {
            v.pb(__builtin_popcount(((a[i] >> 15) ^ x)) - __builtin_popcount(((a[i + 1] >> 15) ^ x)));
        }
        if(mp[v]) ans = mp[v] | (x << 15);
        return ;
    }
    dfs2(i + 1,x);
    dfs2(i + 1,x | (1 << i));
}

int main() {
#ifndef ONLINE_JUDGE
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
#endif

    scanf("%d",&n);
    for(int i = 1;i <= n;++ i) scanf("%d",&a[i]);
    dfs1(0,0);
    dfs2(0,0);
    printf("%d\n",ans);

#ifndef ONLINE_JUDGE
    cerr << "time: " << 1.0 * (clock() - prostart) / CLOCKS_PER_SEC << " s" << endl;
#endif
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值