📌  相关文章
📜  对 (A, B) 进行计数,使得 A 具有 X,B 具有 Y 个设置位,并且 A+B = C

📅  最后修改于: 2021-09-17 06:51:11             🧑  作者: Mango

给定两个数字 x, y 表示设置位的数量。还给出了一个数字 C。 任务是打印我们可以形成两个数字 A 和 B 的方式的数量,这样 A 有 x 个设置位,B 有 y 个设置位,A+B = C。
例子

Input: X = 1, Y = 1, C = 3 
Output: 2 
So two possible ways are (A = 2 and B = 1) and (A = 1 and B = 2)

Input: X = 2, Y = 2, C = 20 
Output: 3 

方法:上述问题可以使用位掩码DP来解决。

  1. 将大小为64 * 64 * 64 * 24-D DP 数组初始化为 10^18 最多有 64 个设置位,其中 -1
  2. DP 数组的第一个状态存储在 C 中从右开始遍历的位数。第二个状态存储 X 中使用的设置位的数量,第三个状态存储 Y 中使用的设置位的数量。第四个状态是进位位,它指的是我们执行加法运算时产生的进位。
  3. 复发将有4种可能性。我们从最右边的位开始。
  4. 如果 C 处的位位置为 1,则有四种可能在该索引处获得 1。
    • 如果进位为 0,那么我们可以使用 X 中的 1 位和 Y 中的 0 位,反之亦然,不会为下一步产生进位。
    • 如果进位为 1,那么我们可以使用每个位的 1 个设置位,这将为下一步生成进位,否则我们不使用 X 和 Y 的设置位,这不生成进位。
  5. 如果 C 的位位置为 0,则在该位位置有四种可能为 0。
    • 如果进位为 1,那么我们可以使用 X 中的 1 个设置位和 Y 中的 0 位,反之亦然,为下一步生成进位 1。
    • 如果进位为 0,那么我们可以分别使用 X 和 Y 中的 1 和 1,从而为下一步生成进位 1。我们也可以不使用设置位,这样就不会为下一步产生进位。
  6. 所有可能性的总和存储在dp[third][seta][setb][carry] 中以避免重新访问相同的状态。

下面是上述方法的实现:

C++
// C++ implementation of the above approach
#include 
using namespace std;
 
// Initial DP array
int dp[64][64][64][2];
 
// Recursive function to generate
// all combinations of bits
int func(int third, int seta, int setb,
         int carry, int number)
{
 
    // if the state has already been visited
    if (dp[third][seta][setb][carry] != -1)
        return dp[third][seta][setb][carry];
 
    // find if C has no more set bits on left
    int shift = (number >> third);
 
    // if no set bits are left for C
    // and there are no set bits for A and B
    // and the carry is 0, then
    // this combination is possible
    if (shift == 0 and seta == 0 and setb == 0 and carry == 0)
        return 1;
 
    // if no set bits are left for C and
    // requirement of set bits for A and B have exceeded
    if (shift == 0 or seta < 0 or setb < 0)
        return 0;
 
    // Find if the bit is 1 or 0 at
    // third index to the left
    int mask = shift & 1;
 
    dp[third][seta][setb][carry] = 0;
 
    // carry = 1 and bit set = 1
    if ((mask) && carry) {
 
        // since carry is 1, and we need 1 at C's bit position
        // we can use 0 and 0
        // or 1 and 1 at A and B bit position
        dp[third][seta][setb][carry]
                += func(third + 1, seta, setb, 0, number)
                + func(third + 1, seta - 1, setb - 1, 1, number);
    }
 
    // carry = 0 and bit set = 1
    else if (mask && !carry) {
 
        // since carry is 0, and we need 1 at C's bit position
        // we can use 1 and 0
        // or 0 and 1 at A and B bit position
        dp[third][seta][setb][carry]
                += func(third + 1, seta - 1, setb, 0, number)
                + func(third + 1, seta, setb - 1, 0, number);
    }
 
    // carry = 1 and bit set = 0
    else if (!mask && carry) {
 
        // since carry is 1, and we need 0 at C's bit position
        // we can use 1 and 0
        // or 0 and 1 at A and B bit position
        dp[third][seta][setb][carry]
                  += func(third + 1, seta - 1, setb, 1, number)
                  + func(third + 1, seta, setb - 1, 1, number);
    }
 
    // carry = 0 and bit set = 0
    else if (!mask && !carry) {
 
        // since carry is 0, and we need 0 at C's bit position
        // we can use 0 and 0
        // or 1 and 1 at A and B bit position
        dp[third][seta][setb][carry]
                  += func(third + 1, seta, setb, 0, number)
                  + func(third + 1, seta - 1, setb - 1, 1, number);
    }
 
    return dp[third][seta][setb][carry];
}
 
// Function to count ways
int possibleSwaps(int a, int b, int c)
{
 
    memset(dp, -1, sizeof(dp));
 
    // function call that returns the
    // answer
    int ans = func(0, a, b, 0, c);
 
    return ans;
}
 
// Driver Code
int main()
{
 
    int x = 2, y = 2, c = 20;
 
    cout << possibleSwaps(x, y, c);
 
    return 0;
}


Java
// Java implementation of the above approach
import java.util.*;
class GfG {
 
// Initial DP array
static int dp[][][][] = new int[64][64][64][2];
 
// Recursive function to generate
// all combinations of bits
static int func(int third, int seta, int setb,
                int carry, int number)
{
 
    // if the state has already been visited
    if (dp[third][seta][setb][carry] != -1)
        return dp[third][seta][setb][carry];
 
    // find if C has no more set bits on left
    int shift = (number >> third);
 
    // if no set bits are left for C
    // and there are no set bits for A and B
    // and the carry is 0, then
    // this combination is possible
    if (shift == 0 && seta == 0 && setb == 0 && carry == 0)
        return 1;
 
    // if no set bits are left for C and
    // requirement of set bits for A and B have exceeded
    if (shift == 0 || seta < 0 || setb < 0)
        return 0;
 
    // Find if the bit is 1 or 0 at
    // third index to the left
    int mask = shift & 1;
 
    dp[third][seta][setb][carry] = 0;
 
    // carry = 1 and bit set = 1
    if ((mask == 1) && carry == 1) {
 
        // since carry is 1, and we need 1 at C's bit position
        // we can use 0 and 0
        // or 1 and 1 at A and B bit position
        dp[third][seta][setb][carry]
                            += func(third + 1, seta, setb, 0, number)
                            + func(third + 1, seta - 1, setb - 1, 1, number);
    }
 
    // carry = 0 and bit set = 1
    else if (mask == 1 && carry == 0) {
 
        // since carry is 0, and we need 1 at C's bit position
        // we can use 1 and 0
        // or 0 and 1 at A and B bit position
        dp[third][seta][setb][carry]
                                    += func(third + 1, seta - 1, setb, 0, number)
                                    + func(third + 1, seta, setb - 1, 0, number);
    }
 
    // carry = 1 and bit set = 0
    else if (mask == 0 && carry == 1) {
 
        // since carry is 1, and we need 0 at C's bit position
        // we can use 1 and 0
        // or 0 and 1 at A and B bit position
        dp[third][seta][setb][carry] += func(third + 1, seta - 1, setb, 1, number)
                                    + func(third + 1, seta, setb - 1, 1, number);
    }
 
    // carry = 0 and bit set = 0
    else if (mask == 0 && carry == 0) {
 
        // since carry is 0, and we need 0 at C's bit position
        // we can use 0 and 0
        // or 1 and 1 at A and B bit position
        dp[third][seta][setb][carry] += func(third + 1, seta, setb, 0, number)
                                    + func(third + 1, seta - 1, setb - 1, 1, number);
    }
 
    return dp[third][seta][setb][carry];
}
 
// Function to count ways
static int possibleSwaps(int a, int b, int c)
{
    for(int q = 0; q < 64; q++)
    {
        for(int r = 0; r < 64; r++)
        {
            for(int p = 0; p < 64; p++)
            {
                for(int d = 0; d < 2; d++)
                {
                    dp[q][r][p][d] = -1;
                }
            }
        }
    }
     
 
    // function call that returns the
    // answer
    int ans = func(0, a, b, 0, c);
 
    return ans;
}
 
// Driver Code
public static void main(String[] args)
{
 
    int x = 2, y = 2, c = 20;
 
    System.out.println(possibleSwaps(x, y, c));
}
}


Python3
# Python3 implementation of the above approach
 
# Initial DP array
dp = [[[[-1, -1] for i in range(64)]
                 for j in range(64)]
                 for k in range(64)]
 
# Recursive function to generate
# all combinations of bits
def func(third, seta, setb, carry, number):
 
    # if the state has already been visited
    if dp[third][seta][setb][carry] != -1:
        return dp[third][seta][setb][carry]
 
    # find if C has no more set bits on left
    shift = number >> third
 
    # if no set bits are left for C
    # and there are no set bits for A and B
    # and the carry is 0, then
    # this combination is possible
    if (shift == 0 and seta == 0 and
        setb == 0 and carry == 0):
        return 1
 
    # if no set bits are left for C and
    # requirement of set bits for A and B have exceeded
    if (shift == 0 or seta < 0 or setb < 0):
        return 0
 
    # Find if the bit is 1 or 0 at
    # third index to the left
    mask = shift & 1
 
    dp[third][seta][setb][carry] = 0
 
    # carry = 1 and bit set = 1
    if (mask) and carry:
 
        # since carry is 1, and we need 1 at
        # C's bit position we can use 0 and 0
        # or 1 and 1 at A and B bit position
        dp[third][seta][setb][carry] +=\
                func(third + 1, seta, setb, 0, number) + \
                func(third + 1, seta - 1, setb - 1, 1, number)
     
    # carry = 0 and bit set = 1
    elif mask and not carry:
 
        # since carry is 0, and we need 1 at C's
        # bit position we can use 1 and 0
        # or 0 and 1 at A and B bit position
        dp[third][seta][setb][carry] +=\
                func(third + 1, seta - 1, setb, 0, number) + \
                func(third + 1, seta, setb - 1, 0, number)
     
    # carry = 1 and bit set = 0
    elif not mask and carry:
 
        # since carry is 1, and we need 0 at C's
        # bit position we can use 1 and 0
        # or 0 and 1 at A and B bit position
        dp[third][seta][setb][carry] +=\
                func(third + 1, seta - 1, setb, 1, number) + \
                func(third + 1, seta, setb - 1, 1, number)
     
    # carry = 0 and bit set = 0
    elif not mask and not carry:
 
        # since carry is 0, and we need 0 at C's
        # bit position we can use 0 and 0
        # or 1 and 1 at A and B bit position
        dp[third][seta][setb][carry] += \
                func(third + 1, seta, setb, 0, number) + \
                func(third + 1, seta - 1, setb - 1, 1, number)
     
    return dp[third][seta][setb][carry]
 
# Function to count ways
def possibleSwaps(a, b, c):
 
    # function call that returns the answer
    ans = func(0, a, b, 0, c)
    return ans
 
# Driver Code
if __name__ == "__main__":
 
    x, y, c = 2, 2, 20
    print(possibleSwaps(x, y, c))
 
# This code is contributed by Rituraj Jain


C#
// C# implementation of the above approach
using System;
 
class GFG
{
 
// Initial DP array
static int [,,,]dp = new int[64, 64, 64, 2];
 
// Recursive function to generate
// all combinations of bits
static int func(int third, int seta, int setb,
                int carry, int number)
{
 
    // if the state has already been visited
    if (third > -1 && seta > -1 &&
         setb > -1 && carry > -1)
        if(dp[third, seta, setb, carry] != -1)
            return dp[third, seta, setb, carry];
 
    // find if C has no more set bits on left
    int shift = (number >> third);
 
    // if no set bits are left for C
    // and there are no set bits for A and B
    // and the carry is 0, then
    // this combination is possible
    if (shift == 0 && seta == 0 && 
         setb == 0 && carry == 0)
        return 1;
 
    // if no set bits are left for C and
    // requirement of set bits for A and
    // B have exceeded
    if (shift == 0 || seta < 0 || setb < 0)
        return 0;
 
    // Find if the bit is 1 or 0 at
    // third index to the left
    int mask = shift & 1;
 
    dp[third, seta, setb, carry] = 0;
 
    // carry = 1 and bit set = 1
    if ((mask == 1) && carry == 1)
    {
 
        // since carry is 1, and we need 1 at
        // C's bit position, we can use 0 and 0
        // or 1 and 1 at A and B bit position
        dp[third, seta,
           setb, carry] += func(third + 1, seta,
                                setb, 0, number) +
                           func(third + 1, seta - 1,
                                setb - 1, 1, number);
    }
 
    // carry = 0 and bit set = 1
    else if (mask == 1 && carry == 0)
    {
 
        // since carry is 0, and we need 1 at
        // C's bit position, we can use 1 and 0
        // or 0 and 1 at A and B bit position
        dp[third, seta,
           setb, carry] += func(third + 1, seta - 1,
                                  setb, 0, number) +
                           func(third + 1, seta,
                                setb - 1, 0, number);
    }
 
    // carry = 1 and bit set = 0
    else if (mask == 0 && carry == 1)
    {
 
        // since carry is 1, and we need 0 at
        // C's bit position, we can use 1 and 0
        // or 0 and 1 at A and B bit position
        dp[third, seta,
           setb, carry] += func(third + 1, seta - 1,
                                setb, 1, number) +
                           func(third + 1, seta,
                                setb - 1, 1, number);
    }
 
    // carry = 0 and bit set = 0
    else if (mask == 0 && carry == 0)
    {
 
        // since carry is 0, and we need 0 at
        // C's bit position, we can use 0 and 0
        // or 1 and 1 at A and B bit position
        dp[third, seta,
           setb, carry] += func(third + 1, seta,
                                setb, 0, number) +
                           func(third + 1, seta - 1,
                                setb - 1, 1, number);
    }
    return dp[third, seta, setb, carry];
}
 
// Function to count ways
static int possibleSwaps(int a, int b, int c)
{
    for(int q = 0; q < 64; q++)
    {
        for(int r = 0; r < 64; r++)
        {
            for(int p = 0; p < 64; p++)
            {
                for(int d = 0; d < 2; d++)
                {
                    dp[q, r, p, d] = -1;
                }
            }
        }
    }
     
    // function call that returns the
    // answer
    int ans = func(0, a, b, 0, c);
 
    return ans;
}
 
// Driver Code
public static void Main(String[] args)
{
    int x = 2, y = 2, c = 20;
 
    Console.WriteLine(possibleSwaps(x, y, c));
}
}
 
// This code is contributed by Rajput-Ji


输出:
3

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程