📜  K倒置的排列数|套装2

📅  最后修改于: 2021-04-22 06:33:56             🧑  作者: Mango

给定两个整数NK ,任务是计算正好具有K个反转的前N个自然数的排列数。由于计数可能非常大,请以10 9 + 7为模数打印。

例子:

天真的方法:有关解决问题的最简单方法,请参阅上一篇文章。
时间复杂度: O(N * N!)
辅助空间: O(1)

使用自顶向下方法的动态编程有关自顶向下方法的信息,请参阅本文的上一篇文章。
时间复杂度: O(N * K 2 )
辅助空间: O(N * K)

使用自下而上的方法进行动态编程

插图:

请按照以下步骤解决问题:

  • 创建一个辅助数组dp [2] [K + 1] ,其中dp [N] [K]存储(N – 1)个数字的所有排列,其中K =(max(K –(N – 1),0)到K)反演,只需将N数字加一次即可。
  • 使用dp [i%2] [K]将在两行之间互换迭代,并取j = Max(K –(N – 1),0) 。因此dp [N [K] = dp [N-1] [j] + dp [N-1] [j + 1] +…。 + dp [N – 1] [K]
  • 在计算dp [N] [K]时,无需执行此额外的K迭代,因为它可以在O(1)中从dp [N] [K – 1]获得。因此,递归关系由下式给出:
  • 分别在NK上使用变量ij迭代两个嵌套循环,并根据上述递归关系更新每个dp状态。
  • 完成上述步骤后,打印dp [N%2] [K]的值。

下面是上述方法的实现:

C++
// C++ program for the above approach
  
#include 
using namespace std;
  
// Function to count permutations with
// K inversions
int numberOfPermWithKInversion(
    int N, int K)
{
    // Store number of permutations
    // with K inversions
    int dp[2][K + 1];
  
    int mod = 1000000007;
  
    for (int i = 1; i <= N; i++) {
        for (int j = 0; j <= K; j++) {
  
            // If N = 1 only 1 permutation
            // with no inversion
            if (i == 1)
                dp[i % 2][j] = (j == 0);
  
            // For K = 0 only 1 permutation
            // with no inversion
            else if (j == 0)
                dp[i % 2][j] = 1;
  
            // Otherwise Update each dp
            // state as per the reccurrance
            // relation formed
            else
                dp[i % 2][j]
                    = (dp[i % 2][j - 1] % mod
                       + (dp[1 - i % 2][j]
                          - ((max(j - (i - 1), 0) == 0)
                                 ? 0
                                 : dp[1 - i % 2]
                                     [max(j - (i - 1), 0)
                                      - 1])
                          + mod)
                             % mod)
                      % mod;
            ;
        }
    }
  
    // Print final count
    cout << dp[N % 2][K];
}
  
// Driver Code
int main()
{
    // Given N and K
    int N = 3, K = 2;
  
    // Function Call
    numberOfPermWithKInversion(N, K);
  
    return 0;
}


Java
// Java program for the above approach
import java.io.*;
  
class GFG{
  
// Function to count permutations with
// K inversions
static void numberOfPermWithKInversion(int N, int K)
{
      
    // Store number of permutations
    // with K inversions
    int[][] dp = new int[2][K + 1];
  
    int mod = 1000000007;
  
    for(int i = 1; i <= N; i++) 
    {
        for(int j = 0; j <= K; j++) 
        {
              
            // If N = 1 only 1 permutation
            // with no inversion
            if (i == 1)
            {
                dp[i % 2][j] = (j == 0) ? 1 : 0;
            }
  
            // For K = 0 only 1 permutation
            // with no inversion
            else if (j == 0)
                dp[i % 2][j] = 1;
  
            // Otherwise Update each dp
            // state as per the reccurrance
            // relation formed
            else
                dp[i % 2][j] = (dp[i % 2][j - 1] % mod +
                               (dp[1 - i % 2][j] - 
                               ((Math.max(j - (i - 1), 0) == 0) ?
                                   0 : dp[1 - i % 2][Math.max(j - 
                                         (i - 1), 0) - 1]) +
                                         mod) % mod) % mod;
        }
    }
      
    // Print final count
    System.out.println (dp[N % 2][K]);
}
  
// Driver Code
public static void main(String[] args)
{
      
    // Given N and K
    int N = 3, K = 2;
  
    // Function Call
    numberOfPermWithKInversion(N, K);
}
}
  
// This code is contributed by akhilsaini


Python3
# Python3 program for the above approach
  
# Function to count permutations with
# K inversions
def numberOfPermWithKInversion(N, K):
      
    # Store number of permutations
    # with K inversions
    dp = [[0] * (K + 1)] * 2
  
    mod = 1000000007
  
    for i in range(1, N + 1):
        for j in range(0, K + 1):
              
            # If N = 1 only 1 permutation
            # with no inversion
            if (i == 1):
                dp[i % 2][j] = 1 if (j == 0) else 0
  
            # For K = 0 only 1 permutation
            # with no inversion
            elif (j == 0):
                dp[i % 2][j] = 1
  
            # Otherwise Update each dp
            # state as per the reccurrance
            # relation formed
            else:
                var = (0 if (max(j - (i - 1), 0) == 0)
                         else dp[1 - i % 2][max(j - (i - 1), 0) - 1])
                dp[i % 2][j] = ((dp[i % 2][j - 1] % mod +
                                (dp[1 - i % 2][j] -
                                (var) + mod) % mod) % mod)
  
    # Print final count
    print(dp[N % 2][K])
  
# Driver Code
if __name__ == '__main__':
      
    # Given N and K
    N = 3
    K = 2
  
    # Function Call
    numberOfPermWithKInversion(N, K)
  
# This code is contributed by akhilsaini


C#
// C# program for the above approach
using System;
  
class GFG{
  
// Function to count permutations with
// K inversions
static void numberOfPermWithKInversion(int N, int K)
{
      
    // Store number of permutations
    // with K inversions
    int[,] dp = new int[2, K + 1];
  
    int mod = 1000000007;
  
    for(int i = 1; i <= N; i++)
    {
        for(int j = 0; j <= K; j++) 
        {
              
            // If N = 1 only 1 permutation
            // with no inversion
            if (i == 1)
            {
                dp[i % 2, j] = (j == 0) ? 1 : 0;
            }
  
            // For K = 0 only 1 permutation
            // with no inversion
            else if (j == 0)
                dp[i % 2, j] = 1;
  
            // Otherwise Update each dp
            // state as per the reccurrance
            // relation formed
            else
                dp[i % 2, j] = (dp[i % 2, j - 1] % mod + 
                               (dp[1 - i % 2, j] - 
                               ((Math.Max(j - (i - 1), 0) == 0) ?
                                   0 : dp[1 - i % 2, Math.Max(
                                          j - (i - 1), 0) - 1]) +
                                              mod) % mod) % mod;
        }
    }
  
    // Print final count
    Console.WriteLine(dp[N % 2, K]);
}
  
// Driver Code
public static void Main()
{
  
    // Given N and K
    int N = 3, K = 2;
  
    // Function Call
    numberOfPermWithKInversion(N, K);
}
}
  
// This code is contributed by akhilsaini


输出:
2




时间复杂度: O(N * K)
辅助空间: O(K)