Algorithm 增加一组数字,使XOR和为0
我需要一些帮助来解决一个问题,我已将其简化为以下内容。我有N个30位的数字,这样所有数字的组合XOR都是非零的。我需要向N个数字中的每一个数字添加一个非负(0或更多)值,这样新数字的组合XOR在总加法值(而不是加法数)最小化的约束下变为0 例如,如果我将数字(01010)2、(01011)2和(01100)2作为三个数字(N=3)。然后,它们的组合异或为(01101)2。我们可以添加以下数字:Algorithm 增加一组数字,使XOR和为0,algorithm,optimization,bit-manipulation,dynamic-programming,xor,Algorithm,Optimization,Bit Manipulation,Dynamic Programming,Xor,我需要一些帮助来解决一个问题,我已将其简化为以下内容。我有N个30位的数字,这样所有数字的组合XOR都是非零的。我需要向N个数字中的每一个数字添加一个非负(0或更多)值,这样新数字的组合XOR在总加法值(而不是加法数)最小化的约束下变为0 例如,如果我将数字(01010)2、(01011)2和(01100)2作为三个数字(N=3)。然后,它们的组合异或为(01101)2。我们可以添加以下数字: (01010)2+(00001)2=(01011)2:(+1) (01011)2+(10000)2=
- (01010)2+(00001)2=(01011)2:(+1)
- (01011)2+(10000)2=(11011)2:(+16)
- (01100)2+(00100)2=(10000)2:(+4)
- 面具
0 0,我们的意思是之前已经添加了数字i,以及所有较低的位(对于上面的示例,是否有一些原因导致您不能只向其中一个数字添加21?(可能不允许模环绕?)假设第一个数字加上21,只会生成三个数字11111101011 01100,其XOR和不是0。XOR和也应该是0。除了问题中提到的两个约束(XOR变为0,且总相加最小化)之外,没有其他的环绕或其他问题。抱歉-我应该说:有什么原因不能只向其中一个数字添加一个适当的值以获得所需的结果?我不明白为什么需要向多个元素添加一个值?可能重复:@EvgenyKluev这确实是一个重复,但已接受的解决方案不处理最小条件我希望得到一个更完整的答案。#include <iostream> #include <cstdio> #include <cstdlib> #include <string> #include <cstring> #include <cmath> #include <algorithm> #include <vector> #include <set> #include <map> #include <ctime> #include <cassert> using namespace std; #define fs first #define sc second #define pb push_back #define mp make_pair #define range(i, n) for (long long i=0; i<(n); ++i) #define forit(it,v) for(typeof((v).begin()) it = v.begin() ; it != (v).end() ; ++it) #define eprintf(...) fprintf(stderr, __VA_ARGS__),fflush(stderr) #define sz(a) ((int)(a).size()) #define all(a) (a).begin(),a.end() #define two(i) (1LL<<(i)) typedef long long ll; typedef vector<int> VI; typedef pair<int, int> PII; int n; vector<ll> arr; ll ans; map<PII, ll> M; void update(ll & ret, ll tmp) { if (tmp == -1) return; if (ret == -1) ret = tmp; ret = min(ret, tmp); } /* * memoization(mask, pos) * Args: * mask: if 2^i in mask it means arr[i] has been added a high bit before, and all lower bit(<=pos) can be considerd zero. * pos: current check bit position, start from high to low * Return: * return -1 if not valid ans exists else return minimum addition sum */ int memoization(int mask, int pos) { if (pos < 0) { return 0; } PII state = mp(mask, pos); if (M.find(state) != M.end()) { return M[state]; } ll &ret = M[state]; ret = -1; int one_cnt = 0; for (int i = 0; i < n; i++) { if ( !(mask & two(i)) && (two(pos) & arr[i])) { one_cnt ++; } } if (one_cnt % 2 == 0) { // even, xor on this pos equals zero ret = memoization(mask, pos - 1); } else { if (one_cnt == n) { //full odd bad state, do nothing //pass } else { //not full odd, choose one empty bit to place 1 for (int i = 0; i < n; i++) { if ((mask & two(i)) //if number i has been added before, then it contain zero at pos || !(two(pos) & arr[i]) // or if number i has zero at pos and hasn't been added before ) { ll candi = memoization(mask | two(i), pos - 1); ll added = mask & two(i) ? two(pos) // number i has been added before, so we need extra two(pos) sum //number i hasn't been added before, we need calc the new sum //here we only consider bits in [0 .. pos] : two(pos) - arr[i] % two(pos + 1); if (candi >= 0) // legal result update(ret, candi + added); } } } } return ret; } int main() { #ifndef ONLINE_JUDGE freopen("g.in", "r", stdin); #endif while (cin >> n) { arr.clear(); for (int i = 0; i < n; i++) { ll val; cin >> val; arr.push_back(val); } ll max_val = arr[0]; for (int i = 1; i < n; i++) max_val = max(max_val, arr[i]); int max_pos = 0; while (max_val) max_pos ++, max_val >>= 1; max_pos ++; //no adjust M.clear(); ans = memoization(0, 31); bool even_bit = true; for (int i = max_pos; i >= 0; i--) { int one_cnt = 0; for (int j = 0; j < n; j++) one_cnt += (two(i) & arr[j]) > 0; even_bit &= one_cnt % 2 == 0; if (even_bit) { for (int j = 0; j < n; j++) { //arr[j] at pos i is empty, try add to 1 if (!(two(i) & arr[j])) { ll backup = arr[j]; arr[j] = two(i); //since previous pos all contain even one bits, we just start from current pos i M.clear(); ll candi = memoization(0, i); ll added = two(i) - backup % two(i); if (candi >= 0) update(ans, candi + added); arr[j] = backup; } } } } cout << ans << endl; } return 0; }