Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 增加一组数字,使XOR和为0_Algorithm_Optimization_Bit Manipulation_Dynamic Programming_Xor - Fatal编程技术网

Algorithm 增加一组数字,使XOR和为0

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=

我需要一些帮助来解决一个问题,我已将其简化为以下内容。我有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=(11011)2:(+16)
  • (01100)2+(00100)2=(10000)2:(+4)
现在,新数字的总XOR为0,总加法为21(+1+16+4)。该总附加值必须最小化(可能有更好的分布来减少该总附加值,但这只是一个示例)

这些数字各为30位,因此数字可能较大,N算法:

求k,给定数字的异或和的最高有效位的位置(在您的示例中为4)。确定是否所有给定的数字都具有给定的位集(如示例中所示)

如果是,则必须增加给定数字中的两个,这样它们的最高有效位将位于位置k+1。要确定witch,您应该强制所有数字对,并增加其中一个,直到它变为2^(k+1),另一个,直到xor和等于0。然后选择最好的一对

如果没有,那么你只需要增加一个给定的数字,它的第k位是0。要确定这个数字,您应该强制所有这些数字并增加它们,直到xor和等于0。然后选择最好的

要确定其中一个数字应增加多少以使所有数字的异或和变为0,请计算所有其他数字的异或和,并从中减去必须增加的数字。

尼斯问题:)

我提出了一种在O(n*2^n*31*n)中运行的方法,对于n=15,对于一个测试用例来说有点慢(228556800)。详情如下:

我在这里使用dp方法(记忆),我们将状态定义为(int mask,int pos):

  • 面具


    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;
    }