大小为 N 且相邻对的乘积之和等于 K 的二进制数组的计数
给定两个整数N和K ,任务是找到大小为 N 的可能二进制数组的总数,使得该数组中相邻对的乘积之和恰好等于K 。
例子:
Input: N = 5, K = 3
Output: 2
Explanation: Two combinations of array A of size N, whose sum of product of adjacent pairs adds up to K=3.
A = [1, 1, 1, 1, 0]: Value = (1*1) + (1*1) + (1*1) + (1*0) = 3
A = [0, 1, 1, 1, 1]: Value = (0*1) + (1*1) + (1*1) + (1*1) = 3
Input: N = 5, K = 4
Output: 1
Explanation:
A = [1, 1, 1, 1, 1]: Value = (1*1) + (1*1) + (1*1) + (1*1) = 4
Input: N=2, K=3
Output: 0
朴素方法:最简单的方法是找到数组的所有可能组合,并单独检查每个组合是否其和等于 K。
时间复杂度:
高效方法:上述简单方法可以通过在大小为 (K+1, N+1, 2) 的 3d 矩阵 dp 中记忆每个递归调用的结果来优化,即 dp[K+1][N+1][ 2]。在这里,这个 dp 矩阵的每个节点,比如dp[a][b]表示大小b具有总和a并且最后一个元素是c的可能组合的数量,其中 c 只能是 0 或 1。现在按照以下步骤解决这个问题:
- 首先,创建一个带参数的函数组合(N, idx, prev, val, K) ,其中N是要形成的数组的大小, idx是数组的所有可能组合都可能的索引(最初为 0) , prev是新形成的数组中的前一个元素(只能是 0 或 1), val是直到 idx 的乘积之和, K是连续元素的乘积之和。此函数将返回可能组合的数量,直到索引idx具有 sum val和前一个元素prev 。此外,在返回时记住结果。
- 现在,从主函数调用上述函数combinationsPossible两次,所有初始值相同,但仅将prev 更改为一次为0,另一次为1,以计算从0 和1 开始的所有数组的可能组合。
- 在每次通话中检查基本情况,即:
- 如果val>K :返回 0,因为在此索引之后有 0 个组合的总和 K 已超过总和。
- 如果idx=N-1 :这意味着形成了大小为 N 的整个数组。因此,如果val为K ,则只返回 1,即可能的组合数。否则,返回 0。
- 此外,在每个递归调用中,检查其结果是否已被记忆。如果是,那么只需从dp数组中返回它。
- 现在,如果前一个元素是 1,则进行两次递归调用:
- 考虑以 1 作为当前元素的可能组合。因此,在此调用中将val增加 1,因为当前元素和前一个元素的乘积 (1*1=1) 将为当前总和加 1。
- 考虑以 0 作为当前元素的可能组合。在这种情况下, val将保持不变。
- 如果前一个元素为 0,则还进行两次递归调用,一次将带有 1 的组合视为当前元素,另一个将带有 0 的组合视为当前元素。在这两种情况下, val都将保持不变。
- 将上述四个函数调用返回的所有值相加,记忆后从当前函数返回这个相加值。
- 根据以上观察打印答案。
下面是上述方法的实现:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to return the number of total
// possible combinations of 0 and 1 to form
// an array of size N having sum of product
// of consecutive elements K
int combinationsPossible(int N, int idx, int prev, int val,
int K,
vector > >& dp)
{
// If value is greater than K, then
// return 0 as no combination is
// possible to have sum K
if (val > K) {
return 0;
}
// Check if the result of this recursive
// call is memoised already, if it is then
// just return the previously calculated result
if (dp[val][idx][prev] != -1) {
return dp[val][idx][prev];
}
// Check if the value is equal to K at N, if
// it is then return 1 as this combination
// is possible. Otherwise return 0.
if (idx == N - 1) {
if (val == K) {
return 1;
}
return 0;
}
int ans = 0;
// If previous element is 1
if (prev == 1) {
// If current element is 1 as well, then
// add 1 to value
ans += combinationsPossible(N, idx + 1, 1, val + 1,
K, dp);
// If current element is 0, then value
// will remain same
ans += combinationsPossible(N, idx + 1, 0, val, K,
dp);
}
// If previous element is 0, then value will
// remain same irrespective of the current element
else {
ans += combinationsPossible(N, idx + 1, 1, val, K,
dp);
ans += combinationsPossible(N, idx + 1, 0, val, K,
dp);
}
// Memoise and return the ans
return dp[val][idx][prev] = ans;
}
// Driver Code
int main()
{
int N = 5;
int K = 3;
vector > > dp(
K + 1,
vector >(N + 1, vector(2, -1)));
// As the array can be started by 0 or 1, so take both
// cases while calculating the total possible
// combinations
cout << (combinationsPossible(N, 0, 0, 0, K, dp)
+ combinationsPossible(N, 0, 1, 0, K, dp));
}
Java
// Java program for the above approach
import java.util.*;
class GFG
{
// Function to return the number of total
// possible combinations of 0 and 1 to form
// an array of size N having sum of product
// of consecutive elements K
static int combinationsPossible(int N, int idx, int prev,
int val, int K, int[][][] dp)
{
// If value is greater than K, then
// return 0 as no combination is
// possible to have sum K
if (val > K) {
return 0;
}
// Check if the result of this recursive
// call is memoised already, if it is then
// just return the previously calculated result
if (dp[val][idx][prev] != -1) {
return dp[val][idx][prev];
}
// Check if the value is equal to K at N, if
// it is then return 1 as this combination
// is possible. Otherwise return 0.
if (idx == N - 1) {
if (val == K) {
return 1;
}
return 0;
}
int ans = 0;
// If previous element is 1
if (prev == 1) {
// If current element is 1 as well, then
// add 1 to value
ans += combinationsPossible(N, idx + 1, 1, val + 1, K, dp);
// If current element is 0, then value
// will remain same
ans += combinationsPossible(N, idx + 1, 0, val, K, dp);
}
// If previous element is 0, then value will
// remain same irrespective of the current element
else {
ans += combinationsPossible(N, idx + 1, 1, val, K, dp);
ans += combinationsPossible(N, idx + 1, 0, val, K, dp);
}
// Memoise and return the ans
dp[val][idx][prev] = ans;
return dp[val][idx][prev];
}
// Driver Code
public static void main(String[] args) {
int N = 5;
int K = 3;
int[][][] dp = new int[K + 1][N + 1][2];
for (int i = 0; i < K + 1; i++) {
for (int j = 0; j < N + 1; j++) {
for (int k = 0; k < 2; k++)
dp[i][j][k] = -1;
}
}
// As the array can be started by 0 or 1, so take both
// cases while calculating the total possible
// combinations
System.out.print(combinationsPossible(N, 0, 0, 0, K, dp) + combinationsPossible(N, 0, 1, 0, K, dp));
}
}
// This code is contributed by 29AjayKumar
Python3
# Python 3 program for the above approach
# Function to return the number of total
# possible combinations of 0 and 1 to form
# an array of size N having sum of product
# of consecutive elements K
def combinationsPossible(N, idx, prev, val, K, dp):
# If value is greater than K, then
# return 0 as no combination is
# possible to have sum K
if (val > K):
return 0
# Check if the result of this recursive
# call is memoised already, if it is then
# just return the previously calculated result
if (dp[val][idx][prev] != -1):
return dp[val][idx][prev]
# Check if the value is equal to K at N, if
# it is then return 1 as this combination
# is possible. Otherwise return 0.
if (idx == N - 1):
if(val == K):
return 1
return 0
ans = 0
# If previous element is 1
if (prev == 1):
# If current element is 1 as well, then
# add 1 to value
ans += combinationsPossible(N, idx + 1, 1, val + 1, K, dp)
# If current element is 0, then value
# will remain same
ans += combinationsPossible(N, idx + 1, 0, val, K, dp)
# If previous element is 0, then value will
# remain same irrespective of the current element
else:
ans += combinationsPossible(N, idx + 1, 1, val, K, dp)
ans += combinationsPossible(N, idx + 1, 0, val, K, dp)
# Memoise and return the ans
dp[val][idx][prev] = ans
return ans
# Driver Code
if __name__ == '__main__':
N = 5
K = 3
dp = [[[-1 for i in range(2)] for j in range(N+1)] for k in range(K+1)]
# As the array can be started by 0 or 1, so take both
# cases while calculating the total possible
# combinations
print(combinationsPossible(N, 0, 0, 0, K, dp) + combinationsPossible(N, 0, 1, 0, K, dp))
# This code is contributed by SURENDRA_GANGWAR.
C#
// C# program for the above approach
using System;
class GFG
{
// Function to return the number of total
// possible combinations of 0 and 1 to form
// an array of size N having sum of product
// of consecutive elements K
static int combinationsPossible(int N, int idx,
int prev, int val,
int K, int[, , ] dp)
{
// If value is greater than K, then
// return 0 as no combination is
// possible to have sum K
if (val > K) {
return 0;
}
// Check if the result of this recursive
// call is memoised already, if it is then
// just return the previously calculated result
if (dp[val, idx, prev] != -1) {
return dp[val, idx, prev];
}
// Check if the value is equal to K at N, if
// it is then return 1 as this combination
// is possible. Otherwise return 0.
if (idx == N - 1) {
if (val == K) {
return 1;
}
return 0;
}
int ans = 0;
// If previous element is 1
if (prev == 1) {
// If current element is 1 as well, then
// add 1 to value
ans += combinationsPossible(N, idx + 1, 1,
val + 1, K, dp);
// If current element is 0, then value
// will remain same
ans += combinationsPossible(N, idx + 1, 0, val,
K, dp);
}
// If previous element is 0, then value will
// remain same irrespective of the current element
else {
ans += combinationsPossible(N, idx + 1, 1, val,
K, dp);
ans += combinationsPossible(N, idx + 1, 0, val,
K, dp);
}
// Memoise and return the ans
return dp[val, idx, prev] = ans;
}
// Driver Code
public static void Main()
{
int N = 5;
int K = 3;
int[, , ] dp = new int[K + 1, N + 1, 2];
for (int i = 0; i < K + 1; i++)
for (int j = 0; j < N + 1; j++)
for (int l = 0; l < 2; l++)
dp[i, j, l] = -1;
// As the array can be started by 0 or 1, so take
// both cases while calculating the total possible
// combinations
Console.WriteLine(
combinationsPossible(N, 0, 0, 0, K, dp)
+ combinationsPossible(N, 0, 1, 0, K, dp));
}
}
// This code is contributed by ukasp.
Javascript
2
时间复杂度: O(N*K)