F. Make Them Similar ( 暴力折半枚举 + 小技巧 )
Posted willems
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了F. Make Them Similar ( 暴力折半枚举 + 小技巧 )相关的知识,希望对你有一定的参考价值。
题意: 给你 n 个数 a[ 1 ] ~ a[ n ], n <= 100; 让你找一个 x , 使得 a[ 1 ] = a[ 1 ] ^ x ~ a[ n ] = a[ n ] ^ x;
且 a[ 1 ] ~ a[ n ] 的二进制位上的 1 的个数相等。 每个 a[ i ] <= 2^30;
解: a[ i ] <= 2 ^ 30; 那么x也不会超过 2^30; 那我们暴力枚举两个 2 ^ 15;
分别枚举 x 异或上 a[ i ] 的 低 15, 和 x 异或上 a[ i ] 的高15位;
然后我们用 cnt[ 0 ][ 1 ]代表 a[ 1 ] 这个数 异或上你枚举的这个x后, 的低15位上 1 的个数。
cnt[ 1 ][ 1 ] 代表 a[ 1 ] 这个数 异或上你枚举的 这个 x后, 的高 15 位上 1 的个数。
那我们要找到一个 x,使得 cnt[ 0 ][ 1 ] + cnt[ 1 ][ 1 ] = cnt[ 0 ][ 2 ] + cnt[ 1 ][ 2 ] = ...... = cnt[ 0 ][ n ] + cnt[ 1 ][ n ];
那我们是 cnt[ 0 ] 和 cnt[ 1 ] 分开枚举的嘛。
那当我们枚举低15位时。我们就 开个 vector 存一下, cnt[ 0 ] 的 后一位减去前一位。 即 vector 存的是
cnt[ 0 ][ 2 ] - cnt[ 0 ][ 1 ], cnt[ 0 ][ 3 ] - cnt[ 0 ][ 2 ]; ........ cnt[ 0 ][ n ] - cnt[ 0 ][ n - 1 ];
那我们枚举高15位时。 我们的 vector 存的就是 -1 * cnt[ 1 ]的后一位减去前一位。 即
-1 * ( cnt[ 1 ][ 2 ] - cnt[ 1 ][ 1 ] ) ........ -1 * ( cnt[ 1 ][ n ] - cnt[ 1 ][ n - 1 ] );
然后, 当 cnt[ 0 ] 的vector 和 cnt[ 1 ] 的vector 是一样的时候, 就意味着, 每个数的 cnt[ 0 ] + cnt[ 1 ] 是相等的。
因为, cnt[ 0 ][ 2 ] - cnt[ 0 ][ 1 ] = -1 * ( cnt[ 1 ][ 2 ] - cnt[ 1 ][ 1 ] ); 即
cnt[ 0 ][ 2 ] + cnt[ 1 ][ 2 ] = cnt[ 0 ][ 1 ] + cnt[ 1 ][ 1 ];
所以, 我们就找到 x 了, 我们开个 map, 存一下 每个 vector 对应的 状态 (statu);就行了。
#include <bits/stdc++.h> #define LL long long #define rep(i, j, k) for(int i = j; i <= k; i++) #define dep(i, j, k) for(int i = k; i >= j; i--) #define INF 0x3f3f3f3f #define inf 0x3f3f3f3f3f3f3f3f #define mem(i, j) memset(i, j, sizeof(i)) #define pb push_back using namespace std; int ans = -1, n; map < vector< int >, int > mp; vector< int > Q; int a[105]; void dfs1(int num, int statu) { if(num > 15) { Q.clear(); for(int i = 1; i <= n; i++) { Q.push_back(__builtin_popcount((statu ^ a[i]) % (1 << 15))); } for(int i = 1; i < n; i++) { Q[i - 1] = Q[i] - Q[i - 1]; } Q.pop_back(); if(!mp[Q]) mp[Q] = statu; return ; } dfs1(num + 1, statu); dfs1(num + 1, statu | (1 << (num - 1))); } void dfs2(int num, int statu) { if(num > 15) { Q.clear(); for(int i = 1; i <= n; i++) { ///__builtin_popcount(x) 用于计算x的二进制位上1的个数。 Q.push_back(__builtin_popcount(statu ^ (a[i] >> 15))); } for(int i = 1; i < n; i++) { Q[i - 1] = -1 * (Q[i] - Q[i - 1]); } Q.pop_back(); /// 弹出最后一个元素。 if(mp[Q]) { ans = mp[Q] | (statu << 15); } return ; } dfs2(num + 1, statu); dfs2(num + 1, statu | (1 << (num - 1))); } int main() { scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); } dfs1(1, 0); dfs2(1, 0); printf("%d ", ans); return 0; }
以上是关于F. Make Them Similar ( 暴力折半枚举 + 小技巧 )的主要内容,如果未能解决你的问题,请参考以下文章
英语munge symlinks to make them safer怎么翻译?