📜  求阵列中所有无序三元组的xor之和

📅  最后修改于: 2021-04-24 17:08:36             🧑  作者: Mango

给定一个由N个非负整数组成的数组A,求出该数组所有无序三元组的xor之和。对于无序三元组,认为三元组(A [i],A [j],A [k])与三元组(A [j],A [i],A [k])和所有其他排列相同。
由于答案可能很大,请使用10037计算其mod。
例子:

Input : A = [3, 5, 2, 18, 7]
Output : 132

Input : A = [140, 1, 66]
Output : 207




天真的方法
遍历所有无序三元组,然后将每个三元组的xor相加。
高效方法

  • 需要注意的重要一点是,xor在所有位上都是独立的。因此,我们可以分别对每个位进行所需的计算。
  • 让我们考虑所有数组元素的第k位。如果第k个位的x等于1的无整数三元组的数量为C,我们可以简单地将C * 2 k加到答案中。令第k位为1的元素数为X,第k位为0的元素数为Y。然后,可以找到两种情况形成第k位xor等于1的无序三元组:
    1. 这三个元素中只有一个具有第k位1。
    2. 他们三个都具有第k位1。
  • 选择具有第k个比特的3个元素的方式数目1 =

 {X \choose 3}

  • 选择第k个比特为1的元素并剩下0 =的方式的数目

 X * {Y \choose 3}

  • 我们将使用nCr mod p来计算组合函数值。

下面是上述方法的实现。

C++
// C++ program to find sum of xor of
// all unordered triplets of the array
#include 
 
using namespace std;
 
// Iterative Function to calculate
// (x^y)%p in O(log y)
int power(int x, int y, int p)
{
    // Initialize result
    int res = 1;
 
    // Update x if it is more than or
    // equal to p
    x = x % p;
     
 
    while (y > 0)
    {
        // If y is odd, multiply x
        // with result
        if (y & 1)
            res = (res * x) % p;
 
        // y must be even now
        y = y >> 1; // y = y/2
        x = (x * x) % p;
    }
    return res;
}
 
// Returns n^(-1) mod p
int modInverse(int n, int p)
{
    return power(n, p - 2, p);
}
 
// Returns nCr % p using Fermat's little
// theorem.
int nCrModPFermat(int n, int r, int p)
{
    // Base case
    if (r == 0)
        return 1;
    if (n < r)
        return 0;
     
    // Fill factorial array so that we
    // can find all factorial of r, n
    // and n-r
    int fac[n + 1];
    fac[0] = 1;
    for (int i = 1; i <= n; i++)
        fac[i] = fac[i - 1] * i % p;
 
    return (fac[n] * modInverse(fac[r], p) % p
            * modInverse(fac[n - r], p) % p) % p;
}
 
// Function returns sum of xor of all
// unordered triplets of the array
int SumOfXor(int a[], int n)
{
 
    int mod = 10037;
 
    int answer = 0;
 
    // Iterating over the bits
    for (int k = 0; k < 32; k++)
    {
        // Number of elements whith k'th bit
        // 1 and 0 respectively
        int x = 0, y = 0;
 
        for (int i = 0; i < n; i++)
        {
            // Checking if k'th bit is 1
            if (a[i] & (1 << k))
                x++;
            else
                y++;
        }
        // Adding this bit's part to the answer
        answer += ((1 << k) % mod *
                (nCrModPFermat(x, 3, mod)
                    + x * nCrModPFermat(y, 2, mod))
                % mod) % mod;
    }
    return answer;
}
// Drivers code
int main()
{
    int n = 5;
    int A[n] = { 3, 5, 2, 18, 7 };
 
    cout << SumOfXor(A, n);
 
    return 0;
}


Java
// Java program to find sum of xor of
// all unordered triplets of the array
class GFG{
 
// Iterative Function to calculate
// (x^y)%p in O(log y)
static int power(int x, int y, int p)
{
     
    // Initialize result
    int res = 1;
 
    // Update x if it is more than or
    // equal to p
    x = x % p;
 
    while (y > 0)
    {
         
        // If y is odd, multiply x
        // with result
        if ((y & 1) == 1)
            res = (res * x) % p;
 
        // y must be even now
        y = y >> 1; // y = y/2
        x = (x * x) % p;
    }
    return res;
}
 
// Returns n^(-1) mod p
static int modInverse(int n, int p)
{
    return power(n, p - 2, p);
}
 
// Returns nCr % p using Fermat's little
// theorem.
static int nCrModPFermat(int n, int r, int p)
{
     
    // Base case
    if (r == 0)
        return 1;
    if (n < r)
        return 0;
 
    // Fill factorial array so that we
    // can find all factorial of r, n
    // and n-r
    int fac[] = new int[n + 1];
    fac[0] = 1;
    for(int i = 1; i <= n; i++)
        fac[i] = fac[i - 1] * i % p;
 
    return (fac[n] * modInverse(fac[r], p) % p *
                     modInverse(fac[n - r], p) %
                                            p) % p;
}
 
// Function returns sum of xor of all
// unordered triplets of the array
static int SumOfXor(int a[], int n)
{
 
    int mod = 10037;
    int answer = 0;
 
    // Iterating over the bits
    for(int k = 0; k < 32; k++)
    {
         
        // Number of elements whith k'th bit
        // 1 and 0 respectively
        int x = 0, y = 0;
 
        for(int i = 0; i < n; i++)
        {
             
            // Checking if k'th bit is 1
            if ((a[i] & (1 << k)) != 0)
                x++;
            else
                y++;
        }
        // Adding this bit's part to the answer
        answer += ((1 << k) % mod *
                   (nCrModPFermat(x, 3, mod) + x *
                    nCrModPFermat(y, 2, mod)) %
                                        mod) % mod;
    }
    return answer;
}
 
// Driver code
public static void main(String[] args)
{
    int n = 5;
    int A[] = { 3, 5, 2, 18, 7 };
 
    System.out.println(SumOfXor(A, n));
}
}
 
// This code is contributed by jrishabh99


Python3
# Python3 program to find sum of xor of
# all unordered triplets of the array
 
# Iterative Function to calculate
# (x^y)%p in O(log y)
def power(x, y, p):
     
    # Initialize result
    res = 1
 
    # Update x if it is more than or
    # equal to p
    x = x % p
 
    while (y > 0):
        # If y is odd, multiply x
        # with result
        if (y & 1):
            res = (res * x) % p
 
        # y must be even now
        y = y >> 1#y = y/2
        x = (x * x) % p
    return res
 
# Returns n^(-1) mod p
def modInverse(n, p):
    return power(n, p - 2, p)
 
# Returns nCr % p using Fermat's little
# theorem.
def nCrModPFermat(n, r, p):
     
    # Base case
    if (r == 0):
        return 1
    if (n < r):
        return 0
 
    # Fill factorial array so that we
    # can find all factorial of r, n
    # and n-r
    fac = [0]*(n + 1)
    fac[0] = 1
    for i in range(1, n + 1):
        fac[i] = fac[i - 1] * i % p
 
    return (fac[n] * modInverse(fac[r], p) % p *
            modInverse(fac[n - r], p) % p) % p
 
# Function returns sum of xor of all
# unordered triplets of the array
def SumOfXor(a, n):
 
    mod = 10037
 
    answer = 0
 
    # Iterating over the bits
    for k in range(32):
         
        # Number of elements whith k'th bit
        # 1 and 0 respectively
        x = 0
        y = 0
 
        for i in range(n):
             
            # Checking if k'th bit is 1
            if (a[i] & (1 << k)):
                x += 1
            else:
                y += 1
        # Adding this bit's part to the answer
        answer += ((1 << k) % mod * (nCrModPFermat(x, 3, mod)
                    + x * nCrModPFermat(y, 2, mod))
                % mod) % mod
 
    return answer
 
# Drivers code
if __name__ == '__main__':
    n = 5
    A=[3, 5, 2, 18, 7]
 
    print(SumOfXor(A, n))
 
# This code is contributed by mohit kumar 29


C#
// C# program to find sum of xor of
// all unordered triplets of the array
using System;
class GFG{
 
// Iterative Function to calculate
// (x^y)%p in O(log y)
static int power(int x, int y, int p)
{
     
    // Initialize result
    int res = 1;
 
    // Update x if it is more than or
    // equal to p
    x = x % p;
 
    while (y > 0)
    {
         
        // If y is odd, multiply x
        // with result
        if ((y & 1) == 1)
            res = (res * x) % p;
 
        // y must be even now
        y = y >> 1; // y = y/2
        x = (x * x) % p;
    }
    return res;
}
 
// Returns n^(-1) mod p
static int modInverse(int n, int p)
{
    return power(n, p - 2, p);
}
 
// Returns nCr % p using Fermat's little
// theorem.
static int nCrModPFermat(int n, int r, int p)
{
     
    // Base case
    if (r == 0)
        return 1;
    if (n < r)
        return 0;
 
    // Fill factorial array so that we
    // can find all factorial of r, n
    // and n-r
    int []fac = new int[n + 1];
    fac[0] = 1;
    for(int i = 1; i <= n; i++)
        fac[i] = fac[i - 1] * i % p;
 
    return (fac[n] * modInverse(fac[r], p) % p *
                     modInverse(fac[n - r], p) %
                                            p) % p;
}
 
// Function returns sum of xor of all
// unordered triplets of the array
static int SumOfXor(int []a, int n)
{
    int mod = 10037;
    int answer = 0;
 
    // Iterating over the bits
    for(int k = 0; k < 32; k++)
    {
         
        // Number of elements whith k'th bit
        // 1 and 0 respectively
        int x = 0, y = 0;
 
        for(int i = 0; i < n; i++)
        {
             
            // Checking if k'th bit is 1
            if ((a[i] & (1 << k)) != 0)
                x++;
            else
                y++;
        }
        // Adding this bit's part to the answer
        answer += ((1 << k) % mod *
                   (nCrModPFermat(x, 3, mod) + x *
                    nCrModPFermat(y, 2, mod)) %
                                        mod) % mod;
    }
    return answer;
}
 
// Driver code
public static void Main(String[] args)
{
    int n = 5;
    int []A = { 3, 5, 2, 18, 7 };
 
    Console.WriteLine(SumOfXor(A, n));
}
}
 
// This code is contributed by gauravrajput1


输出:
132



时间复杂度: O(32 * N)