📜  N 和 K 组合因子的计数 (nCk)

📅  最后修改于: 2022-05-13 01:56:07.041000             🧑  作者: Mango

N 和 K 组合因子的计数 (nCk)

给定整数NK ,任务是找到N C K的因子数。由于答案可能非常大,因此返回以 998244353 为模的因子数。

例子:

方法:这个问题可以基于以下数学事实来解决:

基于上述事实,可以通过求 M 的质因数及其指数来解决问题。求 M 的素因数,求分子的素因数和分母的素因数

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

  • 使用埃拉托色尼筛法对前 K 个自然数进行素数分解以找到分母的素数。
  • 类似地,对 [N – K +1, N] 范围内的自然数进行质因数分解以找到分子的质因数。
  • 求出N C K的分子和分母中所有项的素因式分解后,使用上式求出N C K的因数个数。

下面是上述方法的实现:

C++
// C++ program to implement the approach
 
#include 
using namespace std;
 
// Function to count the number of factors
int divisorsOfNchooseK(long long N, long long K)
{
 
    // Parameter in time and space complexity
    long long M = max((long long)sqrt(N), K);
 
    // Sieve of eratosthenes for finding prime upto M
    vector prime(M + 1, true);
    prime[0] = prime[1] = false;
    for (long long p = 2; p * p < prime.size(); p++) {
        if (prime[p]) {
            for (long long i = 2 * p; i < prime.size();
                 i += p) {
                prime[i] = false;
            }
        }
    }
 
    // Store the denominator values in deno vector
    vector deno(K + 1);
 
    for (long long i = 1; i <= K; i++) {
        deno[i] = i;
    }
 
    // Store the numerator values in nume vector
    vector nume(K);
 
    long long offset = N - K + 1;
 
    for (long long i = 0; i < K; i++) {
        nume[i] = offset + i;
    }
 
    // Variable for storing answer
    long long ans = 1;
 
    // Iterate through all prime upto M
    for (long long p = 2; p < prime.size(); p++) {
        if (prime[p]) {
            // Store the power of p in
            // prime factorization of C(N, K)
            long long int power = 0;
 
            // Do prime factorization of deno terms
            for (long long i = p; i <= K; i += p) {
                while (deno[i] % p == 0) {
                    power--;
                    deno[i] /= p;
                }
            }
 
            // Do prime factorization of nume terms
            for (long long i
                 = ((N - K + 1) + p - 1) / p * p;
                 i <= N; i += p) {
                while (nume[i - offset] % p == 0) {
                    power++;
                    nume[i - offset] /= p;
                }
            }
            ans *= (power + 1);
            ans %= 998244353;
        }
    }
 
    // Find whether any term in
    // numerator is divisible by some prime
    // greater than √N
    for (long long i = N - K + 1; i <= N; i++) {
        if (nume[i - offset] != 1) {
            ans *= 2; // Coefficient of this prime will be 1
            ans %= 998244353;
        }
    }
 
    return ans;
}
// Driver code
int main()
{
    long long N = 10, K = 3;
 
    // Function call
    int ans = divisorsOfNchooseK(N, K);
    cout << ans;
    return 0;
}


Java
// Java program to implement the approach
import java.util.*;
 
class GFG {
 
  // Function to count the number of factors
  static long divisorsOfNchooseK(long N, long K)
  {
 
    // Parameter in time and space complexity
    long M = Math.max((long)Math.sqrt(N), K);
 
    // Sieve of eratosthenes for finding prime upto M
    boolean[] prime = new boolean[(int)M + 1];
    for (long x = 0; x < M + 1; x++) {
      prime[(int)x] = true;
    }
 
    prime[0] = prime[1] = false;
    for (long p = 2; p * p < prime.length; p++) {
      if (prime[(int)p] == true) {
        for (long i = 2 * p; i < prime.length;
             i += p) {
          prime[(int)i] = false;
        }
      }
    }
 
    // Store the denominator values in deno vector
    long[] deno = new long[(int)K + 1];
 
    for (long i = 1; i <= K; i++) {
      deno[(int)i] = i;
    }
 
    // Store the numerator values in nume vector
    long[] nume = new long[(int)K];
 
    long offset = N - K + 1;
 
    for (long i = 0; i < K; i++) {
      nume[(int)i] = offset + i;
    }
 
    // Variable for storing answer
    long ans = 1;
 
    // Iterate through all prime upto M
    for (long p = 2; p < prime.length; p++) {
      if (prime[(int)p] == true) {
        // Store the power of p in
        // prime factorization of C(N, K)
        long power = 0;
 
        // Do prime factorization of deno terms
        for (long i = p; i <= K; i += p) {
          while (deno[(int)i] % p == 0) {
            power--;
            deno[(int)i] /= p;
          }
        }
 
        // Do prime factorization of nume terms
        for (long i = ((N - K + 1) + p - 1) / p * p;
             i <= N; i += p) {
          while (nume[(int)(i - offset)] % p == 0) {
            power++;
            nume[(int)(i - offset)] /= p;
          }
        }
        ans *= (power + 1);
        ans %= 998244353;
      }
    }
 
    // Find whether any term in
    // numerator is divisible by some prime
    // greater than √N
    for (long i = N - K + 1; i <= N; i++) {
      if (nume[(int)(i - offset)] != 1) {
        ans *= 2; // Coefficient of this prime will
        // be 1
        ans %= 998244353;
      }
    }
 
    return ans;
  }
 
  // Driver code
  public static void main (String[] args) {
    long N = 10, K = 3;
 
    // Function call
    long ans = divisorsOfNchooseK(N, K);
    System.out.print(ans);
  }
}
 
// This code is contributed by hrithikgarg03188.


Python3
# python3 program to implement the approach
 
import math
 
# Function to count the number of factors
def divisorsOfNchooseK(N, K) :
 
 
    # Parameter in time and space complexity
    M = max(int(math.sqrt(N)), K)
 
    # Sieve of eratosthenes for finding prime upto M
    prime = [ True for _ in range(M + 1) ]
    prime[0] = prime[1] = False
    for p in range(2, int(math.sqrt(len(prime)))) :
        if (prime[p]) :
            for i in range(2*p, len(prime), p) :
                prime[i] = False
         
 
    # Store the denominator values in deno vector
    deno = [ 0 for _ in range(K + 1) ]
 
    for i in range(1, K+1) :
        deno[i] = i
     
 
    # Store the numerator values in nume vector
    nume = [ 0 for _ in range(K) ]
 
    offset = N - K + 1
  
 
    for i in range(0, K) :
        nume[i] = offset + i
      
     
    # Variable for storing answer
    ans = 1
 
    # Iterate through all prime upto M
    for p in range(2, len(prime)) :
        if (prime[p]) :
            # Store the power of p in
            # prime factorization of C(N, K)
            power = 0
 
            # Do prime factorization of deno terms
            for i in range(p, K+1, p) :
                while (deno[i] % p == 0) :
                    power -= 1
                    deno[i] //= p
                 
             
            # Do prime factorization of nume terms
            for i in range(((N - K + 1) + p - 1) // p * p, N+1, p) :
                
                while (nume[i - offset] % p == 0) :
                    power += 1
                    nume[i - offset] //= p
                 
             
            ans *= (power + 1)
            ans %= 998244353
     
 
    # Find whether any term in
    # numerator is divisible by some prime
    # greater than √N
    for i in range(N - K + 1, N+1) :
        if (nume[i - offset] != 1) :
            ans *= 2 # Coefficient of this prime will be 1
            ans %= 998244353
 
    return ans
 
# Driver code
if __name__ == "__main__" :
 
    N, K = 10,  3
 
    # Function call
    ans = divisorsOfNchooseK(N, K)
    print(ans)
     
    # This code is contributed by rakeshsahni


C#
// C# program to implement the approach
using System;
class GFG {
 
    // Function to count the number of factors
    static long divisorsOfNchooseK(long N, long K)
    {
 
        // Parameter in time and space complexity
        long M = Math.Max((long)Math.Sqrt(N), K);
 
        // Sieve of eratosthenes for finding prime upto M
        bool[] prime = new bool[M + 1];
        for (long x = 0; x < M + 1; x++) {
            prime[x] = true;
        }
 
        prime[0] = prime[1] = false;
        for (long p = 2; p * p < prime.Length; p++) {
            if (prime[p] == true) {
                for (long i = 2 * p; i < prime.Length;
                     i += p) {
                    prime[i] = false;
                }
            }
        }
 
        // Store the denominator values in deno vector
        long[] deno = new long[K + 1];
 
        for (long i = 1; i <= K; i++) {
            deno[i] = i;
        }
 
        // Store the numerator values in nume vector
        long[] nume = new long[K];
 
        long offset = N - K + 1;
 
        for (long i = 0; i < K; i++) {
            nume[i] = offset + i;
        }
 
        // Variable for storing answer
        long ans = 1;
 
        // Iterate through all prime upto M
        for (long p = 2; p < prime.Length; p++) {
            if (prime[p] == true) {
                // Store the power of p in
                // prime factorization of C(N, K)
                long power = 0;
 
                // Do prime factorization of deno terms
                for (long i = p; i <= K; i += p) {
                    while (deno[i] % p == 0) {
                        power--;
                        deno[i] /= p;
                    }
                }
 
                // Do prime factorization of nume terms
                for (long i = ((N - K + 1) + p - 1) / p * p;
                     i <= N; i += p) {
                    while (nume[i - offset] % p == 0) {
                        power++;
                        nume[i - offset] /= p;
                    }
                }
                ans *= (power + 1);
                ans %= 998244353;
            }
        }
 
        // Find whether any term in
        // numerator is divisible by some prime
        // greater than √N
        for (long i = N - K + 1; i <= N; i++) {
            if (nume[i - offset] != 1) {
                ans *= 2; // Coefficient of this prime will
                          // be 1
                ans %= 998244353;
            }
        }
 
        return ans;
    }
   
    // Driver code
    public static void Main()
    {
        long N = 10, K = 3;
 
        // Function call
        long ans = divisorsOfNchooseK(N, K);
        Console.Write(ans);
    }
}
 
// This code is contributed by Samim Hossain Mondal.


Javascript


输出
16

时间复杂度: O(M * loglogM)
辅助空间: O(M) 其中 M 为最大值(√N, K)